问题 为什么我的系统覆盖所有触摸(不能与底层视图交互)


我有一个启动系统覆盖的服务。当叠加层可见时,我想让它成为可触摸/检测触摸,但我希望保持与它背后的屏幕的交互(后面是指底层活动,例如叠加层旁边)。

我的叠加层是128x128px的位图/ PNG。它被绘制,当我点击它时,我收到了触摸!记录,这很好。 但是当我点击屏幕的任何其他部分(除了叠加层)之外,我得到了触摸!记录并且无法与其下方的屏幕进行交互。

以下是我的代码部分:

主要活动启动服务

buttonStart.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // start Service and return to Homescreen
                Intent i = new Intent(MainActivity.this, MyService.class);
                startService(i);                

                Intent newActivity = new Intent(Intent.ACTION_MAIN); 
                newActivity.addCategory(Intent.CATEGORY_HOME);
                newActivity.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(newActivity);
            }
        });

服务/显示覆盖

@Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        myOverlay = new Overlay(MyService.this);

        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                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.LEFT | Gravity.TOP;

        wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(myOverlay, params);

        myOverlay.setAnimation(new Waiting(MyService.this, 0, 0));
        myOverlay.postInvalidate();

        return super.onStartCommand(intent, flags, startId);
    }

覆盖

public MyOverlay(Context context) {
        super(context);     
        this.context = context;

        setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                Log.i("TOUCH!", event.getAction() + ", x:"+event.getX()+", y:"+event.getY());
                return false;
            }
        });
    }

我究竟做错了什么?还尝试了WindowManager.LayoutParams.TYPE_PHONE而不是WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,但行为相同。

我没有使用Flag FLAG_WATCH_OUTSIDE_TOUCH,那么为什么覆盖层旁边没有注册触摸?

编辑

好像我发现了问题,但仍然不知道如何解决它... 叠加中显示的图像非常小而不是问题,但叠加本身是全屏(!)

我将以下日志添加到Overlay / onTouch()事件:

Log.i("TOUCH!", "View: "+v.toString() +", size="+ v.getWidth()+"/"+v.getHeight());

然后告诉我View:package.overlay.myOverlay, 大小=762分之480

现在我试图通过在服务中添加以下行来强制它不是全屏:

    @Override
        public int onStartCommand(Intent intent, int flags, int startId) {

            myOverlay = new Overlay(MyService.this);
//HERE
myOVerlay.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));

            WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    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.LEFT | Gravity.TOP;

            wm = (WindowManager) getSystemService(WINDOW_SERVICE);
            wm.addView(myOverlay, params);

            myOverlay.setAnimation(new Waiting(MyService.this, 0, 0));
            myOverlay.postInvalidate();

            return super.onStartCommand(intent, flags, startId);
        }

但它没有帮助...仍然myOverlay的大小为480x762 ...为什么它那么大,我怎么能得到它的大小包含图像?


12182
2018-03-06 15:14


起源

你的叠加有多大?它是否涵盖整个底层布局?这是透明的吗? - abbath
“但是我希望保持与它背后的屏幕的交互” - 幸运的是,从Android 4.0.3开始,这是不可能的,以防止tapjacking攻击,至少对于覆盖本身的触摸。叠加层可以接收触摸事件(并且不会转发那些事件)或者不接收触摸事件(类似于 Toast)。 - CommonsWare
@abbath它是一个绘制到画布的128x128 px位图。它有一个透明的背景,是的,这意味着我应该让它不透明,以测试它真的那么小......我会试试看 - Toni Kanoni
@CommonsWare也许互动是假的。我不想互动,我只想获取叠加层上的点击,而例如按主屏幕上的消息图标仍然打开消息应用程序。我很确定我已经看到我的设备(ICS)上的另一个应用程序完成此操作 - Toni Kanoni
“我只想获取叠加层上的点击次数,而例如按主屏幕上的消息图标仍然会打开消息应用” - 如果“消息图标”位于叠加层后面,这应该不再有效,从Android 4.0开始0.3。 - CommonsWare


答案:


这对我有用:

WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.height = WindowManager.LayoutParams.WRAP_CONTENT;
params.width = WindowManager.LayoutParams.WRAP_CONTENT;
params.type = WindowManager.LayoutParams.TYPE_TOAST;
params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

添加时使用此LayoutParams View 到了 WindowManager,它可以阻止它接收任何点击,这是可能的 TYPE_TOAST 已经足够了,但我添加了标志只是为了确保。


11
2017-10-27 06:51



LayoutParams.TYPE_TOAST 不适用于Android O. - Daniel F
params.format = PixelFormat.TRANSLUCENT; 也可能有帮助 - V. Kalyuzhnyu


我也有同样的问题,我通过设置params.width和params.height来解决问题。 尝试这个。

params.width = 128;
params.height = 128;

我希望它会有所帮助。


2
2017-12-12 01:55





我遇到了同样的问题,只是尝试将其添加到您的代码中:

WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY

我非常有信心代码可以工作,如果它不只是检查代码中的其他一些错误,但就触摸而言,这是你的解决方案。无论如何,请告诉我。而我几乎忘记了第二部分,只需将属性更改为matchparent而不是wrapcontent。

祝你好运


-2
2017-10-19 15:09



我认为这与OP想要的相反,这使得您的视图能够捕获所有点击。 - marmor
@marmor,在Android的最新版本中, TYPE_SYSTEM_OVERLAY Windows无法接收触摸事件。 - Sam