| 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | package org.chromium.content.browser; |
| 6 | |
| 7 | import android.util.Log; |
| 8 | import android.view.MotionEvent; |
| 9 | |
| 10 | import org.chromium.base.CalledByNative; |
| 11 | |
| 12 | // This class converts android MotionEvent into an array of touch points so |
| 13 | // that they can be forwarded to the renderer process. |
| 14 | class TouchPoint { |
| 15 | |
| 16 | public static final int CONVERSION_ERROR = -1; |
| 17 | |
| 18 | // Type of motion event to send to the native side. The values originate from their |
| 19 | // webkit WebInputEvent counterparts, and are set via initializeConstants(). |
| 20 | static int TOUCH_EVENT_TYPE_START; |
| 21 | static int TOUCH_EVENT_TYPE_MOVE; |
| 22 | static int TOUCH_EVENT_TYPE_END; |
| 23 | static int TOUCH_EVENT_TYPE_CANCEL; |
| 24 | |
| 25 | // Type of motion event to send to the native side. The values originate from their |
| 26 | // webkit WebTouchPoint counterparts, and are set via initializeConstants(). |
| 27 | private static int TOUCH_POINT_STATE_UNDEFINED; |
| 28 | private static int TOUCH_POINT_STATE_RELEASED; |
| 29 | private static int TOUCH_POINT_STATE_PRESSED; |
| 30 | private static int TOUCH_POINT_STATE_MOVED; |
| 31 | private static int TOUCH_POINT_STATE_STATIONARY; |
| 32 | private static int TOUCH_POINT_STATE_CANCELLED; |
| 33 | |
| 34 | private final int mState; |
| 35 | private final int mId; |
| 36 | private final float mX; |
| 37 | private final float mY; |
| 38 | private final float mSize; |
| 39 | private final float mPressure; |
| 40 | |
| 41 | TouchPoint(int state, int id, float x, float y, float size, float pressure) { |
| 42 | mState = state; |
| 43 | mId = id; |
| 44 | mX = x; |
| 45 | mY = y; |
| 46 | mSize = size; |
| 47 | mPressure = pressure; |
| 48 | } |
| 49 | |
| 50 | // The following methods are called by native to parse the java TouchPoint |
| 51 | // object it has received. |
| 52 | @SuppressWarnings("unused") |
| 53 | @CalledByNative |
| 54 | public int getState() { return mState; } |
| 55 | |
| 56 | @SuppressWarnings("unused") |
| 57 | @CalledByNative |
| 58 | public int getId() { return mId; } |
| 59 | |
| 60 | @SuppressWarnings("unused") |
| 61 | @CalledByNative |
| 62 | public int getX() { return (int) mX; } |
| 63 | |
| 64 | @SuppressWarnings("unused") |
| 65 | @CalledByNative |
| 66 | public int getY() { return (int) mY; } |
| 67 | |
| 68 | @SuppressWarnings("unused") |
| 69 | @CalledByNative |
| 70 | public double getSize() { return mSize; } |
| 71 | |
| 72 | @SuppressWarnings("unused") |
| 73 | @CalledByNative |
| 74 | public double getPressure() { return mPressure; } |
| 75 | |
| 76 | // Converts a MotionEvent into an array of touch points. |
| 77 | // Returns the WebTouchEvent::Type for the MotionEvent and -1 for failure. |
| 78 | public static int createTouchPoints(MotionEvent event, TouchPoint[] pts) { |
| 79 | int type; |
| 80 | int defaultState; |
| 81 | |
| 82 | switch (event.getActionMasked()) { |
| 83 | case MotionEvent.ACTION_DOWN: |
| 84 | type = TOUCH_EVENT_TYPE_START; |
| 85 | defaultState = TOUCH_POINT_STATE_PRESSED; |
| 86 | break; |
| 87 | case MotionEvent.ACTION_MOVE: |
| 88 | type = TOUCH_EVENT_TYPE_MOVE; |
| 89 | defaultState = TOUCH_POINT_STATE_MOVED; |
| 90 | break; |
| 91 | case MotionEvent.ACTION_UP: |
| 92 | type = TOUCH_EVENT_TYPE_END; |
| 93 | defaultState = TOUCH_POINT_STATE_RELEASED; |
| 94 | break; |
| 95 | case MotionEvent.ACTION_CANCEL: |
| 96 | type = TOUCH_EVENT_TYPE_CANCEL; |
| 97 | defaultState = TOUCH_POINT_STATE_CANCELLED; |
| 98 | break; |
| 99 | case MotionEvent.ACTION_POINTER_DOWN: // fall through. |
| 100 | case MotionEvent.ACTION_POINTER_UP: |
| 101 | type = TOUCH_EVENT_TYPE_MOVE; |
| 102 | defaultState = TOUCH_POINT_STATE_STATIONARY; |
| 103 | break; |
| 104 | default: |
| 105 | Log.e("Chromium", "Unknown motion event action: " + event.getActionMasked()); |
| 106 | return CONVERSION_ERROR; |
| 107 | } |
| 108 | |
| 109 | for (int i = 0; i < pts.length; ++i) { |
| 110 | int state = defaultState; |
| 111 | if (defaultState == TOUCH_POINT_STATE_STATIONARY && event.getActionIndex() == i) { |
| 112 | // An additional pointer has started or ended. Map this pointer state as |
| 113 | // required, and all other pointers as "stationary". |
| 114 | state = event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN ? |
| 115 | TOUCH_POINT_STATE_PRESSED : TOUCH_POINT_STATE_RELEASED; |
| 116 | } |
| 117 | pts[i] = new TouchPoint(state, event.getPointerId(i), |
| 118 | event.getX(i), event.getY(i), |
| 119 | event.getSize(i), event.getPressure(i)); |
| 120 | } |
| 121 | |
| 122 | return type; |
| 123 | } |
| 124 | |
| 125 | // This method is called by native to initialize all the constants from |
| 126 | // their counterparts in WebInputEvent and WebTouchPoint. |
| 127 | @SuppressWarnings("unused") |
| 128 | @CalledByNative |
| 129 | private static void initializeConstants( |
| 130 | int touchTypeStart, int touchTypeMove, int touchTypeEnd, int touchTypeCancel, |
| 131 | int touchPointUndefined, int touchPointReleased, int touchPointPressed, |
| 132 | int touchPointMoved, int touchPointStationary, int touchPointCancelled) { |
| 133 | TOUCH_EVENT_TYPE_START = touchTypeStart; |
| 134 | TOUCH_EVENT_TYPE_MOVE = touchTypeMove; |
| 135 | TOUCH_EVENT_TYPE_END = touchTypeEnd; |
| 136 | TOUCH_EVENT_TYPE_CANCEL = touchTypeCancel; |
| 137 | TOUCH_POINT_STATE_UNDEFINED = touchPointUndefined; |
| 138 | TOUCH_POINT_STATE_RELEASED = touchPointReleased; |
| 139 | TOUCH_POINT_STATE_PRESSED = touchPointPressed; |
| 140 | TOUCH_POINT_STATE_MOVED = touchPointMoved; |
| 141 | TOUCH_POINT_STATE_STATIONARY = touchPointStationary; |
| 142 | TOUCH_POINT_STATE_CANCELLED = touchPointCancelled; |
| 143 | } |
| 144 | |
| 145 | /** |
| 146 | * Initialize the constants to distinct values if they have not been initialized. |
| 147 | * During pure-Java testing, initializeConstants() may not be called by native code. |
| 148 | * Unit tests should call this method before using the values. |
| 149 | */ |
| 150 | static void initializeConstantsForTesting() { |
| 151 | if (TOUCH_EVENT_TYPE_START == TOUCH_EVENT_TYPE_MOVE) { |
| 152 | initializeConstants(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); |
| 153 | } |
| 154 | } |
| 155 | } |