我想知道像SwipePad和Wave Launcher这样的应用程序如何能够通过服务检测触摸手势/事件。这些应用程序能够检测到触摸手势,即使它不在自己的活动中。我看过整个互联网,但没有找到他们如何做到这一点。
我的主要问题是服务如何监听触摸客户/事件,就像常规活动可能会收到MotionEvent一样,即使它可能不在原始活动或上下文中。我本质上是在尝试构建一个应用程序,它将从用户那里重新获得特定的触摸手势,无论哪个Activity位于顶部,并在该手势被识别时执行某些操作。触摸重现将是一个在后台作为服务运行的线程。
答案 0 :(得分:18)
我遇到了同样的问题,我终于弄明白了!感谢这篇文章:Creating a system overlay window (always on top)。您需要使用警报窗口而不是叠加层(这也意味着您可以在Andoid ICS中使用它):
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL|WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
然后以这种方式附加一个GestureListener:
GestureDetector gestureDetector = new GestureDetector(this, new AwesomeGestureListener());
View.OnTouchListener gestureListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
};
overlayView.setOnTouchListener(gestureListener);
耶!
答案 1 :(得分:5)
有趣的问题。我不知道他们是怎么做到的,我发现谷歌小组的帖子告诉我没有全球性的触摸倾听者。但无论如何我有一个想法......
我发现this post有人成功地从服务中显示弹出窗口。如果我将该弹出窗口设置为透明和全屏,我确信我可以捕获触摸,因为我可以设置touch interceptor。
修改:请在尝试时报告结果,知道这是否有效会很有趣......
答案 2 :(得分:3)
我测试了所有可能的解决方案,但没有任何工作,有些没有触发触摸事件,他们冻结了屏幕。
所以我做了一些逆向工程,现在发布有效的解决方案
WindowManager.LayoutParams params = new android.view.WindowManager.LayoutParams(0, 0, 0, 0, 2003, 0x40028, -3);
View mView = new View(this);
mView.setOnTouchListener(this);
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mView, params);
答案 3 :(得分:3)
我在API 21和nexus 5上对此进行了测试,并且当系统触发触摸事件时,我能够从服务中记录。但是,MotionEvent对象内的数据(例如坐标)在看似我应用程序包的OUTSIDE时返回0.0。
两个来源 integration, permission
我很好奇为什么event.getX(),event.getY()和event.getPressure()在不在服务所在应用的活动中时返回0.0。
修改强>
此解决方案不会阻止其他侦听器因
而接收由服务承保的触摸事件public boolean onTouch(View v, MotionEvent e){
Log.d(LOG_TAG, "Touch event captured");
return false;
通过返回false,它允许其他侦听器接收事件。
<强> EDIT2 强>
显然,如果当前活动和监听器不共享UID,OS中的输入调度程序会将坐标和压力设置为0,这里是source
答案 4 :(得分:0)
我已经搜索了很多SO线程,但出于安全考虑,我不认为这对系统上的所有软件包都有可能。它当然适用于您自己的应用程序。
窗口管理
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
浮动/叠加布局
floatyView = ((LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate
(R.layout.floating_view, null);
floatyView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d(TAG, "event.x " + event.getX());
Log.d(TAG, "event.y " + event.getY());
if (event.getAction() == MotionEvent.ACTION_UP) {
v.performClick();
}
return false;
}
});
布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@android:color/transparent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>