Warning, /graphics/krita/3rdparty/ext_qt/0001-Android-Introducing-QtInputEventDispatcher.patch is written in an unsupported language. File is not indexed.

0001 From c64c1710cfd9173842da496446e2eb4dfb6b30c0 Mon Sep 17 00:00:00 2001
0002 From: Sharaf Zaman <shzam@sdf.org>
0003 Date: Thu, 6 Oct 2022 08:14:33 +0000
0004 Subject: [PATCH] Android: Introducing QtInputEventDispatcher
0005 
0006 This is a separate thread which receives events from the Android UI
0007 thread and handles the dispatching to Qt's Main Thread.
0008 
0009 The reason for this new thread is to prevent some nasty deadlocks
0010 between Android's UI thread and Qt's MainLoopThread (the deadlocks
0011 happened when UI Thread was stuck trying to dispatch an event or flush
0012 Qt's window system queue and while the Qt Main thread was stuck trying
0013 to get a SurfaceView from Android).
0014 
0015 In addition to just dispatching this patch also moves the event handling
0016 to cpp (if in case in future we ditch java in favor of native_app_glue
0017 for event handling). Everything is ported almost like the way it was
0018 before, because the previous version of event handling worked correctly
0019 on all devices (I remember, display tablets being the odd ones).
0020 ---
0021  .../qt5/android/QtInputEventDispatcher.java   | 119 ++++++++
0022  .../org/qtproject/qt5/android/QtLayout.java   |  12 +-
0023  .../org/qtproject/qt5/android/QtNative.java   | 187 +------------
0024  .../platforms/android/MotionEventWrapper.h    | 157 +++++++++++
0025  .../platforms/android/androidjniinput.cpp     | 255 +++++++++++++-----
0026  .../platforms/android/androidjnimain.cpp      |  18 ++
0027  .../platforms/android/androidjnimain.h        |   2 +
0028  7 files changed, 503 insertions(+), 247 deletions(-)
0029  create mode 100644 src/android/jar/src/org/qtproject/qt5/android/QtInputEventDispatcher.java
0030  create mode 100644 src/plugins/platforms/android/MotionEventWrapper.h
0031 
0032 diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtInputEventDispatcher.java b/src/android/jar/src/org/qtproject/qt5/android/QtInputEventDispatcher.java
0033 new file mode 100644
0034 index 0000000000..15e1c322fe
0035 --- /dev/null
0036 +++ b/src/android/jar/src/org/qtproject/qt5/android/QtInputEventDispatcher.java
0037 @@ -0,0 +1,119 @@
0038 +package org.qtproject.qt5.android;
0039 +
0040 +import android.os.Handler;
0041 +import android.os.Looper;
0042 +import android.os.Message;
0043 +import android.util.Log;
0044 +import android.view.InputDevice;
0045 +import android.view.MotionEvent;
0046 +
0047 +public class QtInputEventDispatcher extends Thread {
0048 +
0049 +    private static final String TAG = "QtInputEventDispatcher";
0050 +
0051 +    private Handler mEventHandler;
0052 +
0053 +    QtInputEventDispatcher() {
0054 +        super(TAG);
0055 +    }
0056 +
0057 +    @Override
0058 +    public void run() {
0059 +        try {
0060 +            Looper.prepare();
0061 +            mEventHandler =
0062 +                    new Handler(
0063 +                            Looper.myLooper(),
0064 +                            new Handler.Callback() {
0065 +                                @Override
0066 +                                public boolean handleMessage(Message msg) {
0067 +                                    MotionEvent event = (MotionEvent) msg.obj;
0068 +                                    if (event != null) {
0069 +                                        dispatchMotionEvent(msg.arg1, msg.arg2 == 1, event);
0070 +                                        event.recycle();
0071 +                                    }
0072 +                                    return true;
0073 +                                }
0074 +                            });
0075 +            Looper.loop();
0076 +        } catch (Exception e) {
0077 +            Log.e(TAG, "Looper halted, error = " + e);
0078 +            e.printStackTrace();
0079 +        }
0080 +    }
0081 +
0082 +    public void onCommonEvent(MotionEvent event, int id) {
0083 +        if (mEventHandler == null) {
0084 +            return;
0085 +        }
0086 +
0087 +        MotionEvent clonedEvent = MotionEvent.obtain(event);
0088 +        Message.obtain(mEventHandler, /*what = */ 0, id, /* arg2 = */ 0, clonedEvent)
0089 +                .sendToTarget();
0090 +    }
0091 +
0092 +    public void onTouchEvent(MotionEvent event, int id) {
0093 +        if (mEventHandler == null) {
0094 +            return;
0095 +        }
0096 +
0097 +        MotionEvent clonedEvent = MotionEvent.obtain(event);
0098 +        // here we set touch to true
0099 +        Message.obtain(mEventHandler, /*what = */ 0, id, /* arg2 = */ 1, clonedEvent)
0100 +                .sendToTarget();
0101 +    }
0102 +
0103 +    public void onLongPress(final MotionEvent event, final int id) {
0104 +        if (mEventHandler == null) {
0105 +            return;
0106 +        }
0107 +
0108 +        Message.obtain(
0109 +                        mEventHandler,
0110 +                        new Runnable() {
0111 +                            @Override
0112 +                            public void run() {
0113 +                                longPress(id, (int) event.getX(), (int) event.getY());
0114 +                            }
0115 +                        })
0116 +                .sendToTarget();
0117 +    }
0118 +
0119 +    public boolean sendGenericMotionEvent(MotionEvent event, int id) {
0120 +        if (!event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
0121 +            return false;
0122 +        }
0123 +
0124 +        if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
0125 +            onCommonEvent(event, id);
0126 +            return canHandleMouseAction(event);
0127 +        } else if ((event.getSource()
0128 +                        & (InputDevice.SOURCE_STYLUS
0129 +                                | InputDevice.SOURCE_TOUCHPAD
0130 +                                | InputDevice.SOURCE_TOUCHSCREEN))
0131 +                != 0) {
0132 +
0133 +            onTouchEvent(event, id);
0134 +            return true;
0135 +        }
0136 +        return false;
0137 +    }
0138 +
0139 +    private static boolean canHandleMouseAction(MotionEvent event) {
0140 +        switch (event.getActionMasked()) {
0141 +            case MotionEvent.ACTION_UP:
0142 +            case MotionEvent.ACTION_DOWN:
0143 +            case MotionEvent.ACTION_HOVER_MOVE:
0144 +            case MotionEvent.ACTION_MOVE:
0145 +            case MotionEvent.ACTION_SCROLL:
0146 +                return true;
0147 +            default:
0148 +                return false;
0149 +        }
0150 +    }
0151 +
0152 +    private static native void dispatchMotionEvent(
0153 +            int winId, boolean isTouchEvent, MotionEvent event);
0154 +
0155 +    private static native void longPress(int winId, int x, int y);
0156 +}
0157 diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java b/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java
0158 index 6b067a9cfd..b74cb6bd8f 100644
0159 --- a/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java
0160 +++ b/src/android/jar/src/org/qtproject/qt5/android/QtLayout.java
0161 @@ -53,24 +53,28 @@ public class QtLayout extends ViewGroup
0162  {
0163      private GestureDetector m_gestureDetector;
0164      private Runnable m_startApplicationRunnable;
0165 +    private QtInputEventDispatcher inputEventDispatcher;
0166  
0167      public QtLayout(Context context, Runnable startRunnable)
0168      {
0169          super(context);
0170          m_startApplicationRunnable = startRunnable;
0171          initializeGestureDetector(context);
0172 +        inputEventDispatcher = QtNative.getInputEventDispatcher();
0173      }
0174  
0175      public QtLayout(Context context, AttributeSet attrs)
0176      {
0177          super(context, attrs);
0178          initializeGestureDetector(context);
0179 +        inputEventDispatcher = QtNative.getInputEventDispatcher();
0180      }
0181  
0182      public QtLayout(Context context, AttributeSet attrs, int defStyle)
0183      {
0184          super(context, attrs, defStyle);
0185          initializeGestureDetector(context);
0186 +        inputEventDispatcher = QtNative.getInputEventDispatcher();
0187      }
0188  
0189      private void initializeGestureDetector(Context context)
0190 @@ -78,7 +82,7 @@ public class QtLayout extends ViewGroup
0191          m_gestureDetector =
0192              new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
0193                  public void onLongPress(MotionEvent event) {
0194 -                    QtNative.longPress(getId(), (int) event.getX(), (int) event.getY());
0195 +                    inputEventDispatcher.onLongPress(event, getId());
0196                  }
0197              });
0198          m_gestureDetector.setIsLongpressEnabled(true);
0199 @@ -278,7 +282,7 @@ public class QtLayout extends ViewGroup
0200  
0201      @Override
0202      public boolean onTouchEvent(MotionEvent event) {
0203 -        QtNative.sendTouchEvent(event, getId());
0204 +        inputEventDispatcher.onTouchEvent(event, getId());
0205          m_gestureDetector.onTouchEvent(event);
0206          return true;
0207      }
0208 @@ -286,13 +290,13 @@ public class QtLayout extends ViewGroup
0209      @Override
0210      public boolean onTrackballEvent(MotionEvent event)
0211      {
0212 -        QtNative.sendTrackballEvent(event, getId());
0213 +        inputEventDispatcher.onCommonEvent(event, getId());
0214          return true;
0215      }
0216  
0217      @Override
0218      public boolean onGenericMotionEvent(MotionEvent event)
0219      {
0220 -        return QtNative.sendGenericMotionEvent(event, getId());
0221 +        return inputEventDispatcher.sendGenericMotionEvent(event, getId());
0222      }
0223  }
0224 diff --git a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
0225 index 8e32a83f9f..9c8ecb0d12 100644
0226 --- a/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
0227 +++ b/src/android/jar/src/org/qtproject/qt5/android/QtNative.java
0228 @@ -99,13 +99,13 @@ public class QtNative
0229      private static double m_displayMetricsYDpi = .0;
0230      private static double m_displayMetricsScaledDensity = 1.0;
0231      private static double m_displayMetricsDensity = 1.0;
0232 -    private static int m_oldx, m_oldy;
0233      private static final int m_moveThreshold = 0;
0234      private static ClipboardManager m_clipboardManager = null;
0235      private static Method m_checkSelfPermissionMethod = null;
0236      private static Boolean m_tabletEventSupported = null;
0237      private static boolean m_usePrimaryClip = false;
0238      public static QtThread m_qtThread = new QtThread();
0239 +    private static final QtInputEventDispatcher sInputEventDispatcher = new QtInputEventDispatcher();
0240      private static Method m_addItemMethod = null;
0241  
0242  
0243 @@ -156,6 +156,10 @@ public class QtNative
0244          }
0245      }
0246  
0247 +    public static QtInputEventDispatcher getInputEventDispatcher() {
0248 +        return sInputEventDispatcher;
0249 +    }
0250 +
0251      public static String[] getStringArray(String joinedString)
0252      {
0253          return joinedString.split(",");
0254 @@ -164,6 +168,8 @@ public class QtNative
0255      // this method loads full path libs
0256      public static void loadQtLibraries(final ArrayList<String> libraries)
0257      {
0258 +        sInputEventDispatcher.start();
0259 +        Log.i(QtTAG, "InputEventDispatcherStarted");
0260          m_qtThread.run(new Runnable() {
0261              @Override
0262              public void run() {
0263 @@ -436,169 +442,6 @@ public class QtNative
0264          });
0265      }
0266  
0267 -    //@ANDROID-9
0268 -    static private int getAction(int index, MotionEvent event)
0269 -    {
0270 -        int action = event.getActionMasked();
0271 -        if (action == MotionEvent.ACTION_MOVE) {
0272 -            int hsz = event.getHistorySize();
0273 -            if (hsz > 0) {
0274 -                float x = event.getX(index);
0275 -                float y = event.getY(index);
0276 -                for (int h = 0; h < hsz; ++h) {
0277 -                    if ( event.getHistoricalX(index, h) != x ||
0278 -                         event.getHistoricalY(index, h) != y )
0279 -                        return 1;
0280 -                }
0281 -                return 2;
0282 -            }
0283 -            return 1;
0284 -        }
0285 -        if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN && index == event.getActionIndex()) {
0286 -            return 0;
0287 -        } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP && index == event.getActionIndex()) {
0288 -            return 3;
0289 -        }
0290 -        return 2;
0291 -    }
0292 -    //@ANDROID-9
0293 -
0294 -    static public boolean sendTouchEvent(MotionEvent event, int id)
0295 -    {
0296 -        int pointerType = 0;
0297 -
0298 -        if (m_tabletEventSupported == null)
0299 -            m_tabletEventSupported = isTabletEventSupported();
0300 -
0301 -        switch (event.getToolType(0)) {
0302 -        case MotionEvent.TOOL_TYPE_STYLUS:
0303 -            pointerType = 1; // QTabletEvent::Pen
0304 -            break;
0305 -        case MotionEvent.TOOL_TYPE_ERASER:
0306 -            pointerType = 3; // QTabletEvent::Eraser
0307 -            break;
0308 -        }
0309 -
0310 -        if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
0311 -            return sendMouseEvent(event, id);
0312 -        } else if (m_tabletEventSupported && pointerType != 0) {
0313 -            final int historySize = event.getHistorySize();
0314 -            for (int h = 0; h < historySize; h++) {
0315 -                float tiltRot = event.getHistoricalAxisValue(MotionEvent.AXIS_TILT, h);
0316 -                float orientation = event.getHistoricalAxisValue(MotionEvent.AXIS_ORIENTATION, h);
0317 -
0318 -                float tiltX = (float) Math.toDegrees(-Math.sin(orientation) * tiltRot);
0319 -                float tiltY = (float) Math.toDegrees(Math.cos(orientation) * tiltRot);
0320 -
0321 -                tabletEvent(id, event.getDeviceId(), event.getHistoricalEventTime(h), event.getActionMasked(),
0322 -                            pointerType, event.getButtonState(), event.getHistoricalX(h),
0323 -                            event.getHistoricalY(h), event.getHistoricalPressure(h), tiltX, tiltY,
0324 -                            (float)Math.toDegrees(orientation), event.getMetaState());
0325 -            }
0326 -            float tiltRot = event.getAxisValue(MotionEvent.AXIS_TILT);
0327 -            float orientation = event.getAxisValue(MotionEvent.AXIS_ORIENTATION);
0328 -            float tiltX = (float) Math.toDegrees(-Math.sin(orientation) * tiltRot);
0329 -            float tiltY = (float) Math.toDegrees(Math.cos(orientation) * tiltRot);
0330 -            tabletEvent(id, event.getDeviceId(), event.getEventTime(), event.getActionMasked(), pointerType,
0331 -                event.getButtonState(), event.getX(), event.getY(), event.getPressure(), tiltX, tiltY,
0332 -                (float) Math.toDegrees(orientation), event.getMetaState());
0333 -            return true;
0334 -        } else {
0335 -            final int historySize = event.getHistorySize();
0336 -            touchBegin(id);
0337 -            // batched ones
0338 -            for (int h = 0; h < historySize; h++) {
0339 -                touchBegin(id);
0340 -                for (int i = 0; i < event.getPointerCount(); ++i) {
0341 -                    touchAdd(id,
0342 -                             event.getPointerId(i),
0343 -                             getAction(i, event),
0344 -                             i == 0,
0345 -                             (int)event.getHistoricalX(i, h),
0346 -                             (int)event.getHistoricalY(i, h),
0347 -                             event.getHistoricalTouchMajor(i, h),
0348 -                             event.getHistoricalTouchMinor(i, h),
0349 -                             event.getHistoricalOrientation(i, h),
0350 -                             event.getHistoricalPressure(i, h));
0351 -                }
0352 -                touchEnd(id, event.getAction());
0353 -            }
0354 -            touchBegin(id);
0355 -            for (int i = 0; i < event.getPointerCount(); ++i) {
0356 -                touchAdd(id,
0357 -                        event.getPointerId(i),
0358 -                        getAction(i, event),
0359 -                        i == 0,
0360 -                        (int)event.getX(i),
0361 -                        (int)event.getY(i),
0362 -                        event.getTouchMajor(i),
0363 -                        event.getTouchMinor(i),
0364 -                        event.getOrientation(i),
0365 -                        event.getPressure(i));
0366 -            }
0367 -            touchEnd(id, event.getAction());
0368 -            return true;
0369 -        }
0370 -    }
0371 -
0372 -    static public void sendTrackballEvent(MotionEvent event, int id)
0373 -    {
0374 -        sendMouseEvent(event,id);
0375 -    }
0376 -
0377 -    static public boolean sendGenericMotionEvent(MotionEvent event, int id)
0378 -    {
0379 -        if (!event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) {
0380 -            return false;
0381 -        }
0382 -
0383 -        if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
0384 -                return sendMouseEvent(event, id);
0385 -        } else if ((event.getSource() & (InputDevice.SOURCE_STYLUS |
0386 -                                         InputDevice.SOURCE_TOUCHPAD |
0387 -                                         InputDevice.SOURCE_TOUCHSCREEN)) != 0) {
0388 -
0389 -            return sendTouchEvent(event, id);
0390 -        }
0391 -        return false;
0392 -    }
0393 -
0394 -    static public boolean sendMouseEvent(MotionEvent event, int id)
0395 -    {
0396 -        switch (event.getActionMasked()) {
0397 -            case MotionEvent.ACTION_UP:
0398 -                mouseUp(id, (int) event.getX(), (int) event.getY(), event.getMetaState());
0399 -                break;
0400 -
0401 -            case MotionEvent.ACTION_DOWN:
0402 -                mouseDown(id, (int) event.getX(), (int) event.getY(), event.getMetaState(), event.getButtonState());
0403 -                m_oldx = (int) event.getX();
0404 -                m_oldy = (int) event.getY();
0405 -                break;
0406 -            case MotionEvent.ACTION_HOVER_MOVE:
0407 -            case MotionEvent.ACTION_MOVE:
0408 -                if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE) {
0409 -                    mouseMove(id, (int) event.getX(), (int) event.getY(), event.getMetaState());
0410 -                } else {
0411 -                    int dx = (int) (event.getX() - m_oldx);
0412 -                    int dy = (int) (event.getY() - m_oldy);
0413 -                    if (Math.abs(dx) > 5 || Math.abs(dy) > 5) {
0414 -                        mouseMove(id, (int) event.getX(), (int) event.getY(), event.getMetaState());
0415 -                        m_oldx = (int) event.getX();
0416 -                        m_oldy = (int) event.getY();
0417 -                    }
0418 -                }
0419 -                break;
0420 -            case MotionEvent.ACTION_SCROLL:
0421 -                mouseWheel(id, (int) event.getX(), (int) event.getY(),
0422 -                        event.getAxisValue(MotionEvent.AXIS_HSCROLL), event.getAxisValue(MotionEvent.AXIS_VSCROLL));
0423 -                break;
0424 -            default:
0425 -                return false;
0426 -        }
0427 -        return true;
0428 -    }
0429 -
0430      public static Context getContext() {
0431          if (m_activity != null)
0432              return m_activity;
0433 @@ -1074,22 +917,6 @@ public class QtNative
0434      public static native void handleOrientationChanged(int newRotation, int nativeOrientation);
0435      // screen methods
0436  
0437 -    // pointer methods
0438 -    public static native void mouseDown(int winId, int x, int y, int modifier, int actionButton);
0439 -    public static native void mouseUp(int winId, int x, int y, int modifiers);
0440 -    public static native void mouseMove(int winId, int x, int y, int modifier);
0441 -    public static native void mouseWheel(int winId, int x, int y, float hdelta, float vdelta);
0442 -    public static native void touchBegin(int winId);
0443 -    public static native void touchAdd(int winId, int pointerId, int action, boolean primary, int x, int y, float major, float minor, float rotation, float pressure);
0444 -    public static native void touchEnd(int winId, int action);
0445 -    public static native void longPress(int winId, int x, int y);
0446 -    // pointer methods
0447 -
0448 -    // tablet methods
0449 -    public static native boolean isTabletEventSupported();
0450 -    public static native void tabletEvent(int winId, int deviceId, long time, int action, int pointerType, int buttonState, float x, float y, float pressure, float tiltX, float tiltY, float rotation, int modifiers);
0451 -    // tablet methods
0452 -
0453      // keyboard methods
0454      public static native void keyDown(int key, int unicode, int modifier, boolean autoRepeat);
0455      public static native void keyUp(int key, int unicode, int modifier, boolean autoRepeat);
0456 diff --git a/src/plugins/platforms/android/MotionEventWrapper.h b/src/plugins/platforms/android/MotionEventWrapper.h
0457 new file mode 100644
0458 index 0000000000..f493d1a2a4
0459 --- /dev/null
0460 +++ b/src/plugins/platforms/android/MotionEventWrapper.h
0461 @@ -0,0 +1,157 @@
0462 +#ifndef __MOTIONEVENTWRAPPER_H_
0463 +#define __MOTIONEVENTWRAPPER_H_
0464 +
0465 +#include <android/input.h>
0466 +
0467 +class MotionEventWrapper
0468 +{
0469 +public:
0470 +    MotionEventWrapper(AInputEvent *inputEvent)
0471 +        : m_motionEvent(inputEvent)
0472 +    {
0473 +    }
0474 +
0475 +    inline int32_t getDeviceId() const { return AInputEvent_getDeviceId(m_motionEvent); }
0476 +
0477 +    inline int32_t getAction() const { return AMotionEvent_getAction(m_motionEvent); }
0478 +
0479 +    inline int32_t getActionMasked() const { return getAction() & AMOTION_EVENT_ACTION_MASK; }
0480 +
0481 +    inline int32_t getActionIndex() const
0482 +    {
0483 +        return (getAction() & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK)
0484 +            >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
0485 +    }
0486 +
0487 +    inline int32_t getToolType(size_t pointerIndex) const
0488 +    {
0489 +        return AMotionEvent_getToolType(m_motionEvent, pointerIndex);
0490 +    }
0491 +
0492 +    inline size_t getHistorySize() const { return AMotionEvent_getHistorySize(m_motionEvent); }
0493 +
0494 +    inline int64_t getHistoricalEventTime(size_t historicalIndex) const
0495 +    {
0496 +        return AMotionEvent_getHistoricalEventTime(m_motionEvent, historicalIndex);
0497 +    }
0498 +
0499 +    inline int64_t getHistoricalEventTimeMs(size_t historicalIndex) const
0500 +    {
0501 +        return getHistoricalEventTime(historicalIndex) / NS_PER_MS;
0502 +    }
0503 +
0504 +    inline float getHistoricalAxisValue(int32_t axis, size_t pointerIndex,
0505 +                                        size_t historicalIndex) const
0506 +    {
0507 +        return AMotionEvent_getHistoricalAxisValue(m_motionEvent, axis, pointerIndex,
0508 +                                                   historicalIndex);
0509 +    }
0510 +
0511 +    inline float getHistoricalX(size_t historicalIndex) const
0512 +    {
0513 +        return getHistoricalX(0, historicalIndex);
0514 +    }
0515 +
0516 +    inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const
0517 +    {
0518 +        return AMotionEvent_getHistoricalX(m_motionEvent, pointerIndex, historicalIndex);
0519 +    }
0520 +
0521 +    inline float getHistoricalY(size_t historicalIndex) const
0522 +    {
0523 +        return getHistoricalY(0, historicalIndex);
0524 +    }
0525 +
0526 +    inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const
0527 +    {
0528 +        return AMotionEvent_getHistoricalY(m_motionEvent, pointerIndex, historicalIndex);
0529 +    }
0530 +
0531 +    inline float getHistoricalPressure(size_t historicalIndex) const
0532 +    {
0533 +        return getHistoricalPressure(0, historicalIndex);
0534 +    }
0535 +
0536 +    inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const
0537 +    {
0538 +        return AMotionEvent_getHistoricalPressure(m_motionEvent, pointerIndex, historicalIndex);
0539 +    }
0540 +
0541 +    float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex)
0542 +    {
0543 +        return AMotionEvent_getHistoricalTouchMajor(m_motionEvent, pointerIndex, historicalIndex);
0544 +    }
0545 +
0546 +    float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex)
0547 +    {
0548 +        return AMotionEvent_getHistoricalTouchMinor(m_motionEvent, pointerIndex, historicalIndex);
0549 +    }
0550 +
0551 +    float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex)
0552 +    {
0553 +        return AMotionEvent_getHistoricalOrientation(m_motionEvent, pointerIndex, historicalIndex);
0554 +    }
0555 +
0556 +    inline int64_t getEventTime() const { return AMotionEvent_getEventTime(m_motionEvent); }
0557 +
0558 +    inline int64_t getEventTimeMs() const { return getEventTime() / NS_PER_MS; }
0559 +
0560 +    inline float getAxisValue(int32_t axis) const
0561 +    {
0562 +        return AMotionEvent_getAxisValue(m_motionEvent, axis, 0);
0563 +    }
0564 +
0565 +    inline float getX(int pointerIndex) const
0566 +    {
0567 +        return AMotionEvent_getX(m_motionEvent, pointerIndex);
0568 +    }
0569 +
0570 +    inline float getX() const { return getX(0); }
0571 +
0572 +    inline float getY(int pointerIndex) const
0573 +    {
0574 +        return AMotionEvent_getY(m_motionEvent, pointerIndex);
0575 +    }
0576 +
0577 +    inline float getY() const { return getY(0); }
0578 +
0579 +    inline float getPressure(int pointerIndex) const
0580 +    {
0581 +        return AMotionEvent_getPressure(m_motionEvent, pointerIndex);
0582 +    }
0583 +
0584 +    inline float getPressure() const { return getPressure(0); }
0585 +
0586 +    inline int32_t getButtonState() const { return AMotionEvent_getButtonState(m_motionEvent); }
0587 +
0588 +    inline int32_t getMetaState() const { return AMotionEvent_getMetaState(m_motionEvent); }
0589 +
0590 +    size_t getPointerCount() const { return AMotionEvent_getPointerCount(m_motionEvent); }
0591 +
0592 +    int32_t getPointerId(size_t pointerIndex) const
0593 +    {
0594 +        return AMotionEvent_getPointerId(m_motionEvent, pointerIndex);
0595 +    }
0596 +
0597 +    float getOrientation(size_t pointerIndex)
0598 +    {
0599 +        return AMotionEvent_getOrientation(m_motionEvent, pointerIndex);
0600 +    }
0601 +
0602 +    float getTouchMajor(size_t pointerIndex)
0603 +    {
0604 +        return AMotionEvent_getTouchMajor(m_motionEvent, pointerIndex);
0605 +    }
0606 +
0607 +    float getTouchMinor(size_t pointerIndex)
0608 +    {
0609 +        return AMotionEvent_getTouchMinor(m_motionEvent, pointerIndex);
0610 +    }
0611 +
0612 +private:
0613 +    AInputEvent *m_motionEvent;
0614 +
0615 +    const static long NS_PER_MS = 1000000;
0616 +};
0617 +
0618 +#endif // __MOTIONEVENTWRAPPER_H_
0619 diff --git a/src/plugins/platforms/android/androidjniinput.cpp b/src/plugins/platforms/android/androidjniinput.cpp
0620 index a4bb8ae1a7..5c1d050dba 100644
0621 --- a/src/plugins/platforms/android/androidjniinput.cpp
0622 +++ b/src/plugins/platforms/android/androidjniinput.cpp
0623 @@ -47,6 +47,7 @@
0624  #include "qandroidplatformintegration.h"
0625  #include "qandroidplatformwindow.h"
0626  #include "qandroidplatformwindowmanager.h"
0627 +#include "MotionEventWrapper.h"
0628  
0629  #include <qpa/qwindowsysteminterface.h>
0630  #include <QTouchEvent>
0631 @@ -69,6 +70,8 @@ namespace QtAndroidInput
0632      static QRect m_softwareKeyboardRect;
0633  
0634      static QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
0635 +    static QHash<int, QPointF> m_lastTouchPointsPos;
0636 +    static QPoint m_mouseDownPos;
0637  
0638      static QPointer<QWindow> m_mouseGrabber;
0639      static int m_mouseActionButton;
0640 @@ -150,7 +153,8 @@ namespace QtAndroidInput
0641          // other window is clicked. Otherwise Qt goes in an undefined state. I'm not 100% sure
0642          // though.
0643          if (focusWindow && (focusWindow->type() == Qt::Popup || focusWindow->type() == Qt::ToolTip)) {
0644 -            focusWindow->hide();
0645 +            QMetaObject::invokeMethod(
0646 +                qApp, [focusWindow]() { focusWindow->hide(); }, Qt::BlockingQueuedConnection);
0647          }
0648  
0649          QAndroidPlatformWindowManager *wm = dynamic_cast<QAndroidPlatformWindowManager *>(window);
0650 @@ -160,13 +164,13 @@ namespace QtAndroidInput
0651              window = wm->realWindow()->window();
0652          }
0653          if (window && !QGuiApplicationPrivate::instance()->isWindowBlocked(window)) {
0654 -            window->raise();
0655 +            QMetaObject::invokeMethod(
0656 +                qApp, [window]() { window->raise(); }, Qt::BlockingQueuedConnection);
0657              QWindowSystemInterface::handleWindowActivated(window, Qt::ActiveWindowFocusReason);
0658          }
0659      }
0660  
0661 -    static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/,
0662 -                          jint x, jint y, jint modifier, jint actionButton)
0663 +    static void mouseDown(float x, float y, jint modifier, jint actionButton)
0664      {
0665          if (m_ignoreMouseEvents)
0666              return;
0667 @@ -189,7 +193,7 @@ namespace QtAndroidInput
0668                                                   mapAndroidModifiers(modifier));
0669      }
0670  
0671 -    static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jint modifiers)
0672 +    static void mouseUp(float x, float y, jint modifiers)
0673      {
0674          QPoint globalPos(x,y);
0675          QWindow *tlw = m_mouseGrabber.data();
0676 @@ -207,7 +211,7 @@ namespace QtAndroidInput
0677          m_mouseGrabber = 0;
0678      }
0679  
0680 -    static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jint modifier)
0681 +    static void mouseMove(float x, float y, jint modifier)
0682      {
0683          if (m_ignoreMouseEvents)
0684              return;
0685 @@ -229,7 +233,7 @@ namespace QtAndroidInput
0686                                                   mapAndroidModifiers(modifier));
0687      }
0688  
0689 -    static void mouseWheel(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y, jfloat hdelta, jfloat vdelta)
0690 +    static void mouseWheel(int x, int y, float hdelta, float vdelta)
0691      {
0692          if (m_ignoreMouseEvents)
0693              return;
0694 @@ -290,38 +294,23 @@ namespace QtAndroidInput
0695                                                   Qt::MouseButtons(Qt::NoButton));
0696      }
0697  
0698 -    static void touchBegin(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/)
0699 +    static void touchBegin()
0700      {
0701          m_touchPoints.clear();
0702      }
0703  
0704 -    static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean primary, jint x, jint y,
0705 -        jfloat major, jfloat minor, jfloat rotation, jfloat pressure)
0706 +    static void touchAdd(int id, Qt::TouchPointState state, bool primary, int x, int y,
0707 +        float major, float minor, float rotation, float pressure)
0708      {
0709 -        Qt::TouchPointState state = Qt::TouchPointStationary;
0710 -        switch (action) {
0711 -        case 0:
0712 -            state = Qt::TouchPointPressed;
0713 -            break;
0714 -        case 1:
0715 -            state = Qt::TouchPointMoved;
0716 -            break;
0717 -        case 2:
0718 -            state = Qt::TouchPointStationary;
0719 -            break;
0720 -        case 3:
0721 -            state = Qt::TouchPointReleased;
0722 -            break;
0723 -        }
0724 -
0725          const int dw = desktopWidthPixels();
0726          const int dh = desktopHeightPixels();
0727          QWindowSystemInterface::TouchPoint touchPoint;
0728          touchPoint.id = id;
0729          touchPoint.pressure = pressure;
0730          touchPoint.rotation = qRadiansToDegrees(rotation);
0731 -        touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh));
0732 +        touchPoint.normalPosition = QPointF(double(x) / dw, double(y) / dh);
0733          touchPoint.state = state;
0734 +
0735          touchPoint.area = QRectF(x - double(minor),
0736                                   y - double(major),
0737                                   double(minor * 2),
0738 @@ -342,7 +331,7 @@ namespace QtAndroidInput
0739          }
0740      }
0741  
0742 -    static void touchEnd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint action)
0743 +    static void touchEnd(int action)
0744      {
0745          if (m_touchPoints.isEmpty())
0746              return;
0747 @@ -374,9 +363,13 @@ namespace QtAndroidInput
0748              QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints);
0749              break;
0750          }
0751 +
0752 +        if (action == AMOTION_EVENT_ACTION_UP || action == AMOTION_EVENT_ACTION_CANCEL) {
0753 +            m_lastTouchPointsPos.clear();
0754 +        }
0755      }
0756  
0757 -    static bool isTabletEventSupported(JNIEnv */*env*/, jobject /*thiz*/)
0758 +    static bool isTabletEventSupported()
0759      {
0760  #if QT_CONFIG(tabletevent)
0761          return true;
0762 @@ -385,9 +378,9 @@ namespace QtAndroidInput
0763  #endif // QT_CONFIG(tabletevent)
0764      }
0765  
0766 -    static void tabletEvent(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint deviceId, jlong time, jint action,
0767 -        jint pointerType, jint buttonState, jfloat x, jfloat y, jfloat pressure, jfloat tiltX, jfloat tiltY, jfloat rotation,
0768 -        jint modifiers)
0769 +    static void tabletEvent(int deviceId, long time, int action, int pointerType, int buttonState,
0770 +                            float x, float y, float pressure, float tiltX, float tiltY,
0771 +                            float rotation, int modifiers)
0772      {
0773  #if QT_CONFIG(tabletevent)
0774          QPointF globalPosF(x, y);
0775 @@ -403,21 +396,6 @@ namespace QtAndroidInput
0776              localPos = platformWindow ? platformWindow->mapFromGlobal(globalPos) : globalPosF;
0777          }
0778  
0779 -        // Galaxy Note with plain Android:
0780 -        // 0 1 0    stylus press
0781 -        // 2 1 0    stylus drag
0782 -        // 1 1 0    stylus release
0783 -        // 0 1 2    stylus press with side-button held
0784 -        // 2 1 2    stylus drag with side-button held
0785 -        // 1 1 2    stylus release with side-button held
0786 -        // Galaxy Note 4 with Samsung firmware:
0787 -        // 0 1 0    stylus press
0788 -        // 2 1 0    stylus drag
0789 -        // 1 1 0    stylus release
0790 -        // 211 1 2  stylus press with side-button held
0791 -        // 213 1 2  stylus drag with side-button held
0792 -        // 212 1 2  stylus release with side-button held
0793 -        // when action == ACTION_UP (1) it's a release; otherwise we say which button is pressed
0794          Qt::MouseButtons buttons = Qt::NoButton;
0795          switch (action) {
0796          case AMOTION_EVENT_ACTION_UP:
0797 @@ -451,6 +429,155 @@ namespace QtAndroidInput
0798  #endif // QT_CONFIG(tabletevent)
0799      }
0800  
0801 +    static AInputEvent *getMotionEventFromJava(JNIEnv *env, jobject motionEventJava)
0802 +    {
0803 +        // From AOSP's AMotionEvent implementation
0804 +        return reinterpret_cast<AInputEvent *>(
0805 +            env->GetLongField(motionEventJava, QtAndroid::motionEventNativePtr()));
0806 +    }
0807 +
0808 +    static QTabletEvent::PointerType getPointerType(int toolType)
0809 +    {
0810 +        if (toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS) {
0811 +            return QTabletEvent::Pen;
0812 +        } else if (toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) {
0813 +            return QTabletEvent::Eraser;
0814 +        }
0815 +        return QTabletEvent::UnknownPointer;
0816 +    }
0817 +
0818 +    static Qt::TouchPointState getTouchPointStateFromAction(const MotionEventWrapper &event,
0819 +                                                            int pointerIndex)
0820 +    {
0821 +        int actionMasked = event.getActionMasked();
0822 +        int actionIndex = event.getActionIndex();
0823 +
0824 +        if (actionMasked == AMOTION_EVENT_ACTION_DOWN
0825 +            || (actionMasked == AMOTION_EVENT_ACTION_POINTER_DOWN && pointerIndex == actionIndex)) {
0826 +            return Qt::TouchPointPressed;
0827 +        } else if (actionMasked == AMOTION_EVENT_ACTION_UP
0828 +                   || (actionMasked == AMOTION_EVENT_ACTION_POINTER_UP
0829 +                       && pointerIndex == actionIndex)) {
0830 +            return Qt::TouchPointReleased;
0831 +        } else {
0832 +            const int dw = desktopWidthPixels();
0833 +            const int dh = desktopHeightPixels();
0834 +
0835 +            const int id = event.getPointerId(pointerIndex);
0836 +            QPointF lastNormalPosition;
0837 +            if (m_lastTouchPointsPos.contains(id)) {
0838 +                lastNormalPosition = m_lastTouchPointsPos[id];
0839 +            }
0840 +            const QPointF currentNormalPosition =
0841 +                QPointF(double(event.getX()) / dw, double(event.getX()) / dh);
0842 +
0843 +            m_lastTouchPointsPos[id] = currentNormalPosition;
0844 +
0845 +            return (currentNormalPosition == lastNormalPosition) ? Qt::TouchPointStationary
0846 +                                                                 : Qt::TouchPointMoved;
0847 +        }
0848 +    }
0849 +
0850 +    static void dispatchMotionEvent(JNIEnv *env, jobject /*thiz*/, jint /*winId*/,
0851 +                                    jboolean isTouchEvent, jobject motionEventJava)
0852 +    {
0853 +        static const bool tabletEventSupported = isTabletEventSupported();
0854 +
0855 +        AInputEvent *motionEvent = getMotionEventFromJava(env, motionEventJava);
0856 +        MotionEventWrapper ev(motionEvent);
0857 +        if (isTouchEvent) {
0858 +            const QTabletEvent::PointerType pointerType = getPointerType(ev.getToolType(0));
0859 +            if (tabletEventSupported && pointerType != QTabletEvent::UnknownPointer) {
0860 +                const size_t historySize = ev.getHistorySize();
0861 +                for (size_t historicalIndex = 0; historicalIndex < historySize; ++historicalIndex) {
0862 +                    const float tiltRot =
0863 +                        ev.getHistoricalAxisValue(AMOTION_EVENT_AXIS_TILT, 0, historicalIndex);
0864 +                    const float orientation = ev.getHistoricalAxisValue(
0865 +                        AMOTION_EVENT_AXIS_ORIENTATION, 0, historicalIndex);
0866 +
0867 +                    const float tiltX = qRadiansToDegrees(-sin(orientation) * tiltRot);
0868 +                    const float tiltY = qRadiansToDegrees(cos(orientation) * tiltRot);
0869 +
0870 +                    const float orientationDegrees = qRadiansToDegrees(orientation);
0871 +
0872 +                    tabletEvent(ev.getDeviceId(), ev.getHistoricalEventTimeMs(historicalIndex),
0873 +                                ev.getActionMasked(), pointerType, ev.getButtonState(),
0874 +                                ev.getHistoricalX(historicalIndex),
0875 +                                ev.getHistoricalY(historicalIndex),
0876 +                                ev.getHistoricalPressure(historicalIndex), tiltX, tiltY,
0877 +                                orientationDegrees, ev.getMetaState());
0878 +                }
0879 +
0880 +                const float tiltRot = ev.getAxisValue(AMOTION_EVENT_AXIS_TILT);
0881 +                const float orientation = ev.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
0882 +
0883 +                const float tiltX = qRadiansToDegrees(-sin(orientation) * tiltRot);
0884 +                const float tiltY = qRadiansToDegrees(cos(orientation) * tiltRot);
0885 +
0886 +                const float orientationDegrees = qRadiansToDegrees(orientation);
0887 +
0888 +                tabletEvent(ev.getDeviceId(), ev.getEventTimeMs(), ev.getActionMasked(),
0889 +                            pointerType, ev.getButtonState(), ev.getX(), ev.getY(),
0890 +                            ev.getPressure(), tiltX, tiltY, orientationDegrees, ev.getMetaState());
0891 +            } else {
0892 +                const int historySize = ev.getHistorySize();
0893 +                // batched ones
0894 +                for (int historicalIndex = 0; historicalIndex < historySize; historicalIndex++) {
0895 +                    touchBegin();
0896 +                    for (size_t i = 0; i < ev.getPointerCount(); ++i) {
0897 +                        touchAdd(ev.getPointerId(i), getTouchPointStateFromAction(ev, i), i == 0,
0898 +                                 (int)ev.getHistoricalX(i, historicalIndex),
0899 +                                 (int)ev.getHistoricalY(i, historicalIndex),
0900 +                                 ev.getHistoricalTouchMajor(i, historicalIndex),
0901 +                                 ev.getHistoricalTouchMinor(i, historicalIndex),
0902 +                                 ev.getHistoricalOrientation(i, historicalIndex),
0903 +                                 ev.getHistoricalPressure(i, historicalIndex));
0904 +                    }
0905 +                    touchEnd(ev.getAction());
0906 +                }
0907 +                touchBegin();
0908 +                for (size_t i = 0; i < ev.getPointerCount(); ++i) {
0909 +                    touchAdd(ev.getPointerId(i), getTouchPointStateFromAction(ev, i), i == 0,
0910 +                             (int)ev.getX(i), (int)ev.getY(i), ev.getTouchMajor(i),
0911 +                             ev.getTouchMinor(i), ev.getOrientation(i), ev.getPressure(i));
0912 +                }
0913 +                touchEnd(ev.getAction());
0914 +            }
0915 +        } else {
0916 +            switch (ev.getActionMasked()) {
0917 +            case AMOTION_EVENT_ACTION_UP:
0918 +                mouseUp((int)ev.getX(), (int)ev.getY(), ev.getMetaState());
0919 +                break;
0920 +
0921 +            case AMOTION_EVENT_ACTION_DOWN:
0922 +                mouseDown((int)ev.getX(), (int)ev.getY(), ev.getMetaState(), ev.getButtonState());
0923 +                m_mouseDownPos.rx() = (int)ev.getX();
0924 +                m_mouseDownPos.ry() = (int)ev.getY();
0925 +                break;
0926 +
0927 +            case AMOTION_EVENT_ACTION_HOVER_MOVE:
0928 +            case AMOTION_EVENT_ACTION_MOVE:
0929 +                if (ev.getToolType(0) == AMOTION_EVENT_TOOL_TYPE_MOUSE) {
0930 +                    mouseMove((int)ev.getX(), (int)ev.getY(), ev.getMetaState());
0931 +                } else {
0932 +                    QPoint delta = QPoint(ev.getX(), ev.getY()) - m_mouseDownPos;
0933 +                    if (fabs(delta.x()) > 5 || fabs(delta.y()) > 5) {
0934 +                        mouseMove((int)ev.getX(), (int)ev.getY(), ev.getMetaState());
0935 +                        m_mouseDownPos.rx() = (int)ev.getX();
0936 +                        m_mouseDownPos.ry() = (int)ev.getY();
0937 +                    }
0938 +                }
0939 +                break;
0940 +
0941 +            case AMOTION_EVENT_ACTION_SCROLL:
0942 +                mouseWheel((int)ev.getX(), (int)ev.getY(),
0943 +                           ev.getAxisValue(AMOTION_EVENT_AXIS_HSCROLL),
0944 +                           ev.getAxisValue(AMOTION_EVENT_AXIS_VSCROLL));
0945 +                break;
0946 +            }
0947 +        }
0948 +    }
0949 +
0950      static int mapAndroidKey(int key)
0951      {
0952          // 0--9        0x00000007 -- 0x00000010
0953 @@ -942,35 +1069,37 @@ namespace QtAndroidInput
0954  
0955      }
0956  
0957 -    static JNINativeMethod methods[] = {
0958 -        {"touchBegin","(I)V",(void*)touchBegin},
0959 -        {"touchAdd","(IIIZIIFFFF)V",(void*)touchAdd},
0960 -        {"touchEnd","(II)V",(void*)touchEnd},
0961 -        {"mouseDown", "(IIIII)V", (void *)mouseDown},
0962 -        {"mouseUp", "(IIII)V", (void *)mouseUp},
0963 -        {"mouseMove", "(IIII)V", (void *)mouseMove},
0964 -        {"mouseWheel", "(IIIFF)V", (void *)mouseWheel},
0965 -        {"longPress", "(III)V", (void *)longPress},
0966 -        {"isTabletEventSupported", "()Z", (void *)isTabletEventSupported},
0967 -        {"tabletEvent", "(IIJIIIFFFFFFI)V", (void *)tabletEvent},
0968 +    const static JNINativeMethod inputDispatcherMethods[] = {
0969 +        {"dispatchMotionEvent", "(IZLandroid/view/MotionEvent;)V", (void *)dispatchMotionEvent},
0970 +        {"longPress", "(III)V", (void *)longPress}};
0971 +
0972 +    const static JNINativeMethod qtNativeMethods[] = {
0973          {"keyDown", "(IIIZ)V", (void *)keyDown},
0974          {"keyUp", "(IIIZ)V", (void *)keyUp},
0975          {"keyboardVisibilityChanged", "(Z)V", (void *)keyboardVisibilityChanged},
0976          {"keyboardGeometryChanged", "(IIII)V", (void *)keyboardGeometryChanged},
0977 -        {"handleLocationChanged", "(III)V", (void *)handleLocationChanged}
0978 -    };
0979 +        {"handleLocationChanged", "(III)V", (void *)handleLocationChanged}};
0980  
0981      bool registerNatives(JNIEnv *env)
0982      {
0983          jclass appClass = QtAndroid::applicationClass();
0984 +        if (env->RegisterNatives(appClass, qtNativeMethods,
0985 +                                 sizeof(qtNativeMethods) / sizeof(qtNativeMethods[0]))
0986 +            < 0) {
0987 +            __android_log_print(ANDROID_LOG_FATAL, "Qt", "RegisterNatives failed");
0988 +            return false;
0989 +        }
0990  
0991 -        if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
0992 -            __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
0993 +        jclass dispatcherClass = QtAndroid::inputDispatcherClass();
0994 +        if (env->RegisterNatives(dispatcherClass, inputDispatcherMethods,
0995 +                                 sizeof(inputDispatcherMethods) / sizeof(inputDispatcherMethods[0]))
0996 +            < 0) {
0997 +            __android_log_print(ANDROID_LOG_FATAL, "Qt", "RegisterNatives failed");
0998              return false;
0999          }
1000  
1001          return true;
1002      }
1003 -}
1004 +    } // namespace QtAndroidInput
1005  
1006  QT_END_NAMESPACE
1007 diff --git a/src/plugins/platforms/android/androidjnimain.cpp b/src/plugins/platforms/android/androidjnimain.cpp
1008 index a60b121979..526eb19a3e 100644
1009 --- a/src/plugins/platforms/android/androidjnimain.cpp
1010 +++ b/src/plugins/platforms/android/androidjnimain.cpp
1011 @@ -83,6 +83,8 @@ static jmethodID m_createSurfaceMethodID = nullptr;
1012  static jobject m_serviceObject = nullptr;
1013  static jmethodID m_setSurfaceGeometryMethodID = nullptr;
1014  static jmethodID m_destroySurfaceMethodID = nullptr;
1015 +static jclass m_inputDispatcherClass = nullptr;
1016 +static jfieldID m_motionEventNativePtrField;
1017  
1018  static int m_pendingApplicationState = -1;
1019  static QBasicMutex m_platformMutex;
1020 @@ -190,6 +192,16 @@ namespace QtAndroid
1021          return m_applicationClass;
1022      }
1023  
1024 +    jclass inputDispatcherClass()
1025 +    {
1026 +        return m_inputDispatcherClass;
1027 +    }
1028 +
1029 +    jfieldID motionEventNativePtr()
1030 +    {
1031 +        return m_motionEventNativePtrField;
1032 +    }
1033 +
1034      jobject activity()
1035      {
1036          return m_activityObject;
1037 @@ -865,6 +877,12 @@ static int registerNatives(JNIEnv *env)
1038                               m_bitmapDrawableClass,
1039                               "<init>",
1040                               "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
1041 +
1042 +        FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtInputEventDispatcher");
1043 +        m_inputDispatcherClass = static_cast<jclass>(env->NewGlobalRef(clazz));
1044 +
1045 +        FIND_AND_CHECK_CLASS("android/view/MotionEvent");
1046 +        GET_AND_CHECK_FIELD(m_motionEventNativePtrField, clazz, "mNativePtr", "J");
1047      }
1048  
1049      return JNI_TRUE;
1050 diff --git a/src/plugins/platforms/android/androidjnimain.h b/src/plugins/platforms/android/androidjnimain.h
1051 index 08f1d50fe3..c04e903ff7 100644
1052 --- a/src/plugins/platforms/android/androidjnimain.h
1053 +++ b/src/plugins/platforms/android/androidjnimain.h
1054 @@ -84,6 +84,8 @@ namespace QtAndroid
1055      JavaVM *javaVM();
1056      AAssetManager *assetManager();
1057      jclass applicationClass();
1058 +    jclass inputDispatcherClass();
1059 +    jfieldID motionEventNativePtr();
1060      jobject activity();
1061      jobject service();
1062  
1063 -- 
1064 2.37.3
1065