Search code examples
javaandroid-viewmotionevent

How to filter out Long Press into a webvir


I am embedding a youtube video in an iFrame using a WebView. I am trying to avoid sending right mouse clicks to the webview and it seems long pressing a webview sends the event to show the menu.contextmenu

I cant access the document of the iFrame from withing JavaScript, so I cant prevent right mouse clicks on the iFrame using JavaScript. Instead I am trying to prevent long presses from being sent to the webview. So have tried to override the webview's onTouch. It turns out the following doesn't pass the long click nor does it pass any click.

@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
   return true;
}

or

@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
   return false;
}

Adding super.onTouchEvent(motionEvent) passes all clicks to the view. So I have tried to filter out long presses in the following way

private long startTime;

@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent motionEvent) {
    if (motionEvent.getAction() == MotionEvent.ACTION_DOWN){
        startTime = System.nanoTime();
    } else if(motionEvent.getAction() == MotionEvent.ACTION_UP && System.nanoTime() - startTime < 19000000){
            super.onTouchEvent(motionEvent);
        }
    }
    return true;
}

Sadly this doesn't send click events if a user quickly lifts the finger after clicking.


Solution

  • Well I managed to do it using gestures. I created an onTouchListener for the webview and set it.

    How it works

    1. The listener runs a Gesture detector and returns true every time
    @Override
    public boolean onTouch(View webview, MotionEvent event) {
        detector.onTouchEvent(event);
        return true;
    }
    
    1. The gesture detector then filters out long clicks.
    @Override
    public boolean onDown(MotionEvent event) {
        return true;
    }
    
    @Override
    public boolean onSingleTapUp(MotionEvent event) {
        return true;
    }
    
    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx, float dy) {
        return true;
    }
    
    1. Since sending events onDown will trigger youtube to receive long presses so instead I create down events only when I want to click or scroll like
    webview.onTouchEvent(MotionEvent.obtain(
        event.getDownTime(),
        event.getEventTime(),
        MotionEvent.ACTION_DOWN,
        event.getX(),
        event.getY(),
        0));
    

    I had to actually have the down event created once on scroll by creating my own condition boolean firstScroll

    1. Lastly I had to send an up event when all is done using the listener
    class RemoteControl implements View.OnTouchListener {
    
        private final GestureDetector detector;
        private boolean firstScroll = true;
    
        public RemoteControl(WebView webview) {
            Context context = webview.getContext();
            detector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
                @Override
                public boolean onDown(MotionEvent event) {
                    return true;
                }
    
                @Override
                public boolean onSingleTapUp(MotionEvent event) {
                    webview.onTouchEvent(MotionEvent.obtain(
                        event.getDownTime(),
                        event.getEventTime(),
                        MotionEvent.ACTION_DOWN,
                        event.getX(),
                        event.getY(),
                        0));
                    webview.onTouchEvent(event);
                    return true;
                }
    
                @Override
                public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx, float dy) {
                    if (firstScroll) {
                        webview.onTouchEvent(MotionEvent.obtain(
                            e1.getDownTime(),
                            e1.getEventTime(),
                            MotionEvent.ACTION_DOWN,
                            e1.getX(),
                            e1.getY(),
                            0));
                        firstScroll = false;
                        }
                    webview.onTouchEvent(e2);
                    return true;
                }
            });
        }
    
        @Override
        public boolean onTouch(View webview, MotionEvent event) {
            webview.performClick();
            detector.onTouchEvent(event);
            if (event.getAction() == MotionEvent.ACTION_UP) {
                webview.onTouchEvent(event);
                firstScroll = true;
            }
            return true;
        }
    }
    

    Credit to this post