I have created a view that displays on top of all applications and windows with the following code:
//These three are our main components.
WindowManager wm;
LinearLayout ll;
WindowManager.LayoutParams ll_lp;
//Just a sample layout parameters.
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
ll_lp = new WindowManager.LayoutParams();
ll_lp.format = PixelFormat.TRANSLUCENT;
ll_lp.height = WindowManager.LayoutParams.FILL_PARENT;
ll_lp.width = WindowManager.LayoutParams.FILL_PARENT;
ll_lp.gravity = Gravity.CLIP_HORIZONTAL | Gravity.TOP;
//This one is necessary.
ll_lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
//Play around with these two.
ll_lp.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
ll_lp.flags = ll_lp.flags | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
//This is our main layout.
ll = new LinearLayout(this);
ll.setBackgroundColor(android.graphics.Color.argb(50, 255, 255, 255));
ll.setHapticFeedbackEnabled(true);
ll.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Toast.makeText(getApplicationContext(), "TOUCHED", Toast.LENGTH_SHORT).show();
return false;
}
});
//And finally we add what we created to the screen.
wm.addView(ll, ll_lp);
Because FLAG_NOT_TOUCHABLE is set, it only displays the view but doesn't receive any touch events. The application behind the view receives all touch events.
However, if i don't set the flag, then only the view receives touches causing the application behind it to not receive any.
Is there a way for both the view and the application behind it to receive touches? I have tried returning false but still the same.
Any help would be greatly appreciated!
If im not mistaking, the view thats in the background is not receiving touch events because its being filtered out by the system to prevent "click jacking" exploits.
You might be able to get around this system feature by turning off the filtering of touch events for the view in the background using the View.setFilterTouchesWhenObscured(Boolean) method.
Related
I'm new to the accessibility stuff on Android. While going through the classes and documentation I came across TYPE_ACCESSIBILITY_OVERLAY inside the WindowManager class.
The documentation says (only the relevant text)
For example, if there is a full screen accessibility overlay that is
touchable, the windows below it will be introspectable by an
accessibility service even though they are covered by a touchable
window.
So I set out to achieve just that, a full screen accessibility overlay and try to introspect the windows below it
Extended AccessibilityService and added my full screen overlay when onServiceConnected is called (the inspiration for adding overlay came from here)
#Override
protected void onServiceConnected() {
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
FrameLayout mLayout = new FrameLayout(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
lp.format = PixelFormat.TRANSLUCENT;
lp.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.MATCH_PARENT;
lp.gravity = Gravity.TOP;
wm.addView(mLayout, lp);
mLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// Here I'm getting the touch events on the overlay I added
return false;
}
});
}
Now, the question is, how do I introspect or find the windows below this overlay? Even in the onAccessibilityEvent callback I get just this overlay window. getWindows() always has a size of 1. Doesn't it refute the assertion made above for TYPE_ACCESSIBILITY_OVERLAY?
Relevant info: To receive the touch events on the overlay I have disabled touchExplorationMode in the service settings
android:canRequestTouchExplorationMode="false"
What you seem to be missing is flagRetrieveInteractiveWindows on your configuration. These properties and window layout paremeters configuration should work, without requiring for you to disable canRequestTouchExplorationMode in order to get the events and having getWindows return the AccessibilityWindowInfo instances underneath yours:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:packageNames="test.demo.com.tests"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFlags="flagRetrieveInteractiveWindows|flagReportViewIds|flagIncludeNotImportantViews"
android:accessibilityFeedbackType="feedbackAllMask"
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"
/>
And on service connected:
#Override
protected void onServiceConnected() {
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
FrameLayout layout = new FrameLayout(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS|
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP;
windowManager.addView(layout, params);
layout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
//You can either get the information here or on onAccessibilityEvent
return false;
}
});
}
EDIT:
Added FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS to accomplish full screen and removed canRequestTouchExplorationMode since the flag associated to this property should not be included and, therefore, of no use.
I want to detect pressing of a back button in service. I've just tried this code but it didn't show me any log. Can somebody explain me why? And what should I do to make it work?
The whole idea of doing this was was taken from this tutorial http://www.kpbird.com/2013/03/android-detect-global-touch-event.html
public class MyService extends Service implements View.OnKeyListener{
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
LinearLayout touchLayout = new LinearLayout(this);
// set layout width 30 px and height is equal to full screen
LayoutParams lp = new LayoutParams(30, LayoutParams.MATCH_PARENT);
touchLayout.setLayoutParams(lp);
touchLayout.setBackgroundColor(Color.RED);
touchLayout.setOnKeyListener(this);
WindowManager mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
// set layout parameter of window manager
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(
30, // width of layout 30 px
WindowManager.LayoutParams.MATCH_PARENT, // height is equal to full screen
WindowManager.LayoutParams.TYPE_PHONE, // Type Phone, These are non-application windows providing user interaction with the phone (in particular incoming calls).
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, // this window won't ever get key input focus
PixelFormat.TRANSLUCENT);
mParams.gravity = Gravity.LEFT | Gravity.TOP;
mWindowManager.addView(touchLayout, mParams);
}
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK){
Log.v("Point","KeyCode_Back");
return false;
}
return false;
}
}
Your Service is not a View, implementing a View.OnKeyListener does not deliver your desired functionality.
A Service is intended to be an "Activity without UI" which runs in the background of your application. You can use Binders/Broadcasts to communicate with your service but UI interaction is best left to Activity/Fragments.
Annex:
I guess you are trying to build a overlay like in the link you posted in the comment. This Tutorial is from 2013 so things have changed.
In general the Android system discourages App beheaviour like the below described method. Coding like this, goes into the category Lockscreen/Kiosk-App behaviour which is considered as malware.
If you want to accomplish a little side menu inside your app you can do this perfectly fine without using such a service. Outside your App you still have the options of using widgets, which are more user friendly than hardcoding something on the screen.
I am working on a project on android studio. I need to detect whether the screen is touched or not in a background service (and pop up a message for that). But, I have problem detecting whether the screen is touched or not in a background service without affecting user using the smartphone.
When I say "detect in background", I mean the effect of the app will not interfere with what the user is doing on the screen. My progress below should explain what i mean here:
I made an app that will detect whether the user touch the screen in background by implementing onTouchListener in android and use a layout for that onTouchListener. I did this by following the instruction in the website
"http://kpbird.blogspot.com.au/2013/03/android-detect-global-touch-event.html"
and I made some changes to the layout to cover the whole screen so it can detect the whole screen.
But, after I ran my app which created the service that keeps detecting screen touch, every time when the user touch the screen, that touch is absorbed by my service (the layout), so the user can't properly use their phone anymore (like pressing an icon to start other apps). This is because the layout covers the whole screen and blocking any touch info to the icon underneath it (the layout detect screen touch), so the icon don't know there is a touch and hence will not react to user. But I want my app and service to allow the user to use their phone normally.
I heard that the service in android is designed to not interact with user (i.e. screen touches) and work in background, but I want to know if there is a way around this.
Below is the code of my service:
public class GlobalTouchService extends Service implements OnTouchListener{
private String TAG = this.getClass().getSimpleName();
// window manager
private WindowManager mWindowManager;
// linear layout will use to detect touch event
private LinearLayout touchLayout;
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
// create linear layout
touchLayout = new LinearLayout(this);
// set layout width 30 px and height is equal to full screen
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
touchLayout.setLayoutParams(lp);
// set color if you want layout visible on screen
//touchLayout.setBackgroundColor(Color.CYAN);
// set on touch listener
touchLayout.setOnTouchListener(this);
// fetch window manager object
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
// set layout parameter of window manager
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT, // width is equal to full screen
WindowManager.LayoutParams.MATCH_PARENT, // height is equal to full screen
WindowManager.LayoutParams.TYPE_PHONE, // Type Phone, These are non-application windows providing user interaction with the phone (in particular incoming calls).
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, // this window won't ever get key input focus
PixelFormat.TRANSLUCENT);
mParams.gravity = Gravity.LEFT | Gravity.TOP;
Log.i(TAG, "add View");
mWindowManager.addView(touchLayout, mParams);
}
#Override
public void onDestroy() {
if(mWindowManager != null) {
if(touchLayout != null) mWindowManager.removeView(touchLayout);
}
super.onDestroy();
}
public void showAlert(View view) {
AlertDialog.Builder myAlertBuilder = new AlertDialog.Builder(this);
myAlertBuilder.setMessage(getString(R.string.alertMessage))
.setTitle(getString(R.string.alertTitle))
.setPositiveButton(getString(R.string.alertPositiveChoice), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setNegativeButton(getString(R.string.alertNegativeChoice), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
onDestroy();
}
});
AlertDialog myAlert = myAlertBuilder.create();
myAlert.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
myAlert.show();
}
#Override
public boolean onTouch(View v, MotionEvent event) {
//if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_UP)
// Log.i(TAG, "Action :" + event.getAction() + "\t X :" + event.getRawX() + "\t Y :" + event.getRawY());
////////////////////
View myView = null;
//showAlert(myView);
///////////////////////
return false;
}
}
You have onTouch method there. Just return false and touch won't be absorbed by your app.
Please also check this:
https://stackoverflow.com/a/6384443/1723095
Edit:
It's probably not what you want but if you have rooted device you can do something like that:
adb shell getevent dev/input/event1
In my case event1 is responsible for touch events but it can differ.
I am trying to write a Adobe air native extension to catch mouse wheel on android.
Android is getting the mouse wheel event when I am testing it as a native application.
But when I try to package that code as a native extension, I am not getting the event.
I follow this tutorial.
Could I add a listener to the current view?
Am I missing something else?
Is there a mouse wheel extension for mouse wheel in android?
public class OpenAppANE extends Activity implements FREExtension, OnTouchListener {
public void startMouseEvent()
{
LinearLayout touchLayout = new LinearLayout(this);
// set layout width 30 px and height is equal to full screen
LayoutParams lp = new LayoutParams(30, LayoutParams.MATCH_PARENT);
touchLayout.setLayoutParams(lp);
// set color if you want layout visible on screen
// touchLayout.setBackgroundColor(Color.CYAN);
// set on touch listener
touchLayout.setOnTouchListener(this);
// fetch window manager object
WindowManager mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
// set layout parameter of window manager
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(30,
// width of layout 30 px
WindowManager.LayoutParams.MATCH_PARENT, // height is equal to full screen
WindowManager.LayoutParams.TYPE_PHONE, // Type Phone, These are non-application windows providing user interaction with the phone (in particular incoming calls).
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, // this window won't ever get key input focus
PixelFormat.TRANSLUCENT);
mParams.gravity = Gravity.LEFT | Gravity.TOP;
Log.i("TAG", "add View");
mWindowManager.addView(touchLayout, mParams);
}
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
Toast.makeText(appContext, "inside onGenericMotionEvent" , Toast.LENGTH_SHORT ).show();
}
}
There is a MOUSE_WHEEL listener for Air.
I would just use
stage.addEventListener(MouseEvent.MOUSE_WHEEL, onMouseWheelEvent);
to listen for mouse wheel event. should work fine.
ALL Mouse events should work on Android Native.
also use 'delta'
to set the number of lines that that each notch on the mouse wheel represents.
check out: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/InteractiveObject.html#event:mouseWheel also
I want make an app/service that looks like (Nexus One touch buttons)
for the navigation keys (Home, menu, Back, Search)
The buttons should always stay on top and send the command to the actually app that's running.
Someone have ideas and sample codes how to do that?
Update:
I also see and test an app which shows a "cracked display" always on top
so that technique maybe should be useful to always show the buttons on top.
Those function, show the button and catch the "touch event" and send the event
to the active program should be in a service module which runs in background.
You cannot do this kind of application. First, you cannot keep an app always on top, then you cannot dispatch key events to other apps.
You could do this:
WindowManager mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
System.out.println("Accesibilty cargado correctametne");
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mTopView = (ViewGroup) inflater.inflate(R.layout.resourceshower, null);
LayoutParams mWmlp = new WindowManager.LayoutParams(
LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT);
mWmlp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
mWmlp.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
mWmlp.width = 100; //size of window
mWmlp.height = 50;//size of window
mWmlp.format = PixelFormat.TRANSPARENT;
mWmlp.x =50; //position of window
mWmlp.y = 50; //position of window
mWindowManager.addView(mTopView, mWmlp);
Then if you want to get button clicks inside it, in the layout you are inflating (R.layout.resourceshower) on the buttons add this: android:onClick="launch"
and create a public method with the same name like: public void launch(View v){..}
you must create this method in the service/activity you create the floating window.