Search code examples
androidreactjsxamarinwebviewtouch

Is it possible to make android webview based app less sensitive in interpreting taps as small drags?


I have and C# Xamarin android app that hosts a reactjs app in a webview.

When using this app on a touch screen android device, It appears that occasionally tapping the screen is ignored.

What appears to be going on is that, the tap is interpreted as a mini drag event, as there was some small directional movement in the tap.

Looking at the android logs, for failed taps, I noticed output like the following:

adb -d logcat -s CustomFrequencyManagerService

06-19 13:35:49.225  2945  9989 D CustomFrequencyManagerService: acquireDVFSLockLocked : type : DVFS_MIN_LIMIT  frequency : 839000  uid : 1000  pid : 2945  pkgName : GESTURE_DETECTED@CPU_MIN@49
06-19 13:35:49.781  2945  2945 D CustomFrequencyManagerService: releaseDVFSLockLocked : Getting Lock type frm List : DVFS_MIN_LIMIT  frequency : 839000  uid : 1000  pid : 2945  tag : GESTURE_DETECTED@CPU_MIN@49

Note the GESTURE_DETECTED part of the log entry.

However for successful taps, CustomFrequencyManagerService has no output in the log.

Looking at this from the reactjs app perspective:

I noticed that the failed taps emit the following events:

touchstart
touchend

While the normal successful events are:

touchstart
touchend
mousedown
blur
mouseup
click

I could potentially change the reactjs app to respond directly to touch events instead of click events, but I was wondering if there was a way (hopefully programmatically via android app) to alter the sensitivity with regard to what's interpreted as a drag as opposed to a click?

By installing a IOnTouchListener on the Android.WebKit.WebView

_webView.SetOnTouchListener(new GestureIgnoreTouchListener());

I was able to see at what movement threshold a click turned into a drag.

    public class GestureIgnoreTouchListener : Java.Lang.Object, Android.Views.View.IOnTouchListener
    {
        float _x;
        float _y;

        public bool OnTouch(Android.Views.View v, MotionEvent e)
        {
            if (e.Action == MotionEventActions.Down)
            {
                _x = e.RawX;
                _y = e.RawY;
                
                return false;
            }
            if (e.Action == MotionEventActions.Up)
            {
                var diffX = e.RawX - _x;
                var diffY = e.RawY - _y;

                var distance = Math.Sqrt(Math.Pow(diffX, 2) + Math.Pow(diffY, 2));
                // observed: 
                // if distance is 10 or less then this is interpreted as a click.
                // if distance is 12 or greater, click is not emitted.
                Console.WriteLine(distance);

                return false;
            }

            return false;
        }
    }

Ideally, if the distance was between 10 and 50, I would like to be able to make this be considered a click not a drag. Possibly I could create a synthetic click event, in this case, but I'm hoping I can somehow influence what ever android code is responsible for interpreting this as a drag.


Solution

  • There are two approaches I've seen people use for this situation. The first you already mentioned: tell react when you're in touch screen environment to use tap events instead of click events.

    The second is to take into account what Android refers to as "touch slop":

    From https://developer.android.com/training/gestures/movement.html:

    Because finger-based touch isn't always the most precise form of interaction, detecting touch events is often based more on movement than on simple contact. To help apps distinguish between movement-based gestures (such as a swipe) and non-movement gestures (such as a single tap), Android includes the notion of "touch slop". Touch slop refers to the distance in pixels a user's touch can wander before the gesture is interpreted as a movement-based gesture. For more discussion of this topic, see Managing Touch Events in a ViewGroup.

    Google provides an example of one way to deal with it in a difference context here: https://developer.android.com/training/gestures/viewgroup#vc which you could probably adapt to your situation.