mobile/android/base/GeckoEvent.java

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mobile/android/base/GeckoEvent.java	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,819 @@
     1.4 +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +package org.mozilla.gecko;
    1.10 +
    1.11 +import org.mozilla.gecko.gfx.DisplayPortMetrics;
    1.12 +import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
    1.13 +import org.mozilla.gecko.mozglue.JNITarget;
    1.14 +import org.mozilla.gecko.mozglue.generatorannotations.GeneratorOptions;
    1.15 +import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI;
    1.16 +import org.mozilla.gecko.mozglue.RobocopTarget;
    1.17 +
    1.18 +import android.content.res.Resources;
    1.19 +import android.graphics.Point;
    1.20 +import android.graphics.PointF;
    1.21 +import android.graphics.Rect;
    1.22 +import android.hardware.Sensor;
    1.23 +import android.hardware.SensorEvent;
    1.24 +import android.hardware.SensorManager;
    1.25 +import android.location.Address;
    1.26 +import android.location.Location;
    1.27 +import android.os.Build;
    1.28 +import android.os.SystemClock;
    1.29 +import android.util.DisplayMetrics;
    1.30 +import android.util.Log;
    1.31 +import android.util.SparseArray;
    1.32 +import android.view.KeyEvent;
    1.33 +import android.view.MotionEvent;
    1.34 +
    1.35 +import java.nio.ByteBuffer;
    1.36 +import java.util.concurrent.ArrayBlockingQueue;
    1.37 +
    1.38 +/* We're not allowed to hold on to most events given to us
    1.39 + * so we save the parts of the events we want to use in GeckoEvent.
    1.40 + * Fields have different meanings depending on the event type.
    1.41 + */
    1.42 +
    1.43 +/* This class is referenced by Robocop via reflection; use care when
    1.44 + * modifying the signature.
    1.45 + */
    1.46 +@JNITarget
    1.47 +public class GeckoEvent {
    1.48 +    private static final String LOGTAG = "GeckoEvent";
    1.49 +
    1.50 +    private static final int EVENT_FACTORY_SIZE = 5;
    1.51 +
    1.52 +    // Maybe we're probably better to just make mType non final, and just store GeckoEvents in here...
    1.53 +    private static SparseArray<ArrayBlockingQueue<GeckoEvent>> mEvents = new SparseArray<ArrayBlockingQueue<GeckoEvent>>();
    1.54 +
    1.55 +    public static GeckoEvent get(NativeGeckoEvent type) {
    1.56 +        synchronized (mEvents) {
    1.57 +            ArrayBlockingQueue<GeckoEvent> events = mEvents.get(type.value);
    1.58 +            if (events != null && events.size() > 0) {
    1.59 +                return events.poll();
    1.60 +            }
    1.61 +        }
    1.62 +
    1.63 +        return new GeckoEvent(type);
    1.64 +    }
    1.65 +
    1.66 +    public void recycle() {
    1.67 +        synchronized (mEvents) {
    1.68 +            ArrayBlockingQueue<GeckoEvent> events = mEvents.get(mType);
    1.69 +            if (events == null) {
    1.70 +                events = new ArrayBlockingQueue<GeckoEvent>(EVENT_FACTORY_SIZE);
    1.71 +                mEvents.put(mType, events);
    1.72 +            }
    1.73 +
    1.74 +            events.offer(this);
    1.75 +        }
    1.76 +    }
    1.77 +
    1.78 +    // Make sure to keep these values in sync with the enum in
    1.79 +    // AndroidGeckoEvent in widget/android/AndroidJavaWrappers.h
    1.80 +    @JNITarget
    1.81 +    private enum NativeGeckoEvent {
    1.82 +        NATIVE_POKE(0),
    1.83 +        KEY_EVENT(1),
    1.84 +        MOTION_EVENT(2),
    1.85 +        SENSOR_EVENT(3),
    1.86 +        LOCATION_EVENT(5),
    1.87 +        IME_EVENT(6),
    1.88 +        DRAW(7),
    1.89 +        SIZE_CHANGED(8),
    1.90 +        APP_BACKGROUNDING(9),
    1.91 +        APP_FOREGROUNDING(10),
    1.92 +        LOAD_URI(12),
    1.93 +        NOOP(15),
    1.94 +        BROADCAST(19),
    1.95 +        VIEWPORT(20),
    1.96 +        VISITED(21),
    1.97 +        NETWORK_CHANGED(22),
    1.98 +        THUMBNAIL(25),
    1.99 +        SCREENORIENTATION_CHANGED(27),
   1.100 +        COMPOSITOR_CREATE(28),
   1.101 +        COMPOSITOR_PAUSE(29),
   1.102 +        COMPOSITOR_RESUME(30),
   1.103 +        NATIVE_GESTURE_EVENT(31),
   1.104 +        IME_KEY_EVENT(32),
   1.105 +        CALL_OBSERVER(33),
   1.106 +        REMOVE_OBSERVER(34),
   1.107 +        LOW_MEMORY(35),
   1.108 +        NETWORK_LINK_CHANGE(36),
   1.109 +        TELEMETRY_HISTOGRAM_ADD(37),
   1.110 +        PREFERENCES_OBSERVE(39),
   1.111 +        PREFERENCES_GET(40),
   1.112 +        PREFERENCES_REMOVE_OBSERVERS(41),
   1.113 +        TELEMETRY_UI_SESSION_START(42),
   1.114 +        TELEMETRY_UI_SESSION_STOP(43),
   1.115 +        TELEMETRY_UI_EVENT(44);
   1.116 +
   1.117 +        public final int value;
   1.118 +
   1.119 +        private NativeGeckoEvent(int value) {
   1.120 +            this.value = value;
   1.121 +        }
   1.122 +    }
   1.123 +
   1.124 +    /**
   1.125 +     * The DomKeyLocation enum encapsulates the DOM KeyboardEvent's constants.
   1.126 +     * @see https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Key_location_constants
   1.127 +     */
   1.128 +    @GeneratorOptions(generatedClassName = "JavaDomKeyLocation")
   1.129 +    @WrapEntireClassForJNI
   1.130 +    public enum DomKeyLocation {
   1.131 +        DOM_KEY_LOCATION_STANDARD(0),
   1.132 +        DOM_KEY_LOCATION_LEFT(1),
   1.133 +        DOM_KEY_LOCATION_RIGHT(2),
   1.134 +        DOM_KEY_LOCATION_NUMPAD(3),
   1.135 +        DOM_KEY_LOCATION_MOBILE(4),
   1.136 +        DOM_KEY_LOCATION_JOYSTICK(5);
   1.137 +
   1.138 +        public final int value;
   1.139 +
   1.140 +        private DomKeyLocation(int value) {
   1.141 +            this.value = value;
   1.142 +        }
   1.143 +    }
   1.144 +
   1.145 +    // Encapsulation of common IME actions.
   1.146 +    @JNITarget
   1.147 +    public enum ImeAction {
   1.148 +        IME_SYNCHRONIZE(0),
   1.149 +        IME_REPLACE_TEXT(1),
   1.150 +        IME_SET_SELECTION(2),
   1.151 +        IME_ADD_COMPOSITION_RANGE(3),
   1.152 +        IME_UPDATE_COMPOSITION(4),
   1.153 +        IME_REMOVE_COMPOSITION(5),
   1.154 +        IME_ACKNOWLEDGE_FOCUS(6);
   1.155 +
   1.156 +        public final int value;
   1.157 +
   1.158 +        private ImeAction(int value) {
   1.159 +            this.value = value;
   1.160 +        }
   1.161 +    }
   1.162 +
   1.163 +    public static final int IME_RANGE_CARETPOSITION = 1;
   1.164 +    public static final int IME_RANGE_RAWINPUT = 2;
   1.165 +    public static final int IME_RANGE_SELECTEDRAWTEXT = 3;
   1.166 +    public static final int IME_RANGE_CONVERTEDTEXT = 4;
   1.167 +    public static final int IME_RANGE_SELECTEDCONVERTEDTEXT = 5;
   1.168 +
   1.169 +    public static final int IME_RANGE_LINE_NONE = 0;
   1.170 +    public static final int IME_RANGE_LINE_DOTTED = 1;
   1.171 +    public static final int IME_RANGE_LINE_DASHED = 2;
   1.172 +    public static final int IME_RANGE_LINE_SOLID = 3;
   1.173 +    public static final int IME_RANGE_LINE_DOUBLE = 4;
   1.174 +    public static final int IME_RANGE_LINE_WAVY = 5;
   1.175 +
   1.176 +    public static final int IME_RANGE_UNDERLINE = 1;
   1.177 +    public static final int IME_RANGE_FORECOLOR = 2;
   1.178 +    public static final int IME_RANGE_BACKCOLOR = 4;
   1.179 +    public static final int IME_RANGE_LINECOLOR = 8;
   1.180 +
   1.181 +    public static final int ACTION_MAGNIFY_START = 11;
   1.182 +    public static final int ACTION_MAGNIFY = 12;
   1.183 +    public static final int ACTION_MAGNIFY_END = 13;
   1.184 +
   1.185 +    private final int mType;
   1.186 +    private int mAction;
   1.187 +    private boolean mAckNeeded;
   1.188 +    private long mTime;
   1.189 +    private Point[] mPoints;
   1.190 +    private int[] mPointIndicies;
   1.191 +    private int mPointerIndex; // index of the point that has changed
   1.192 +    private float[] mOrientations;
   1.193 +    private float[] mPressures;
   1.194 +    private Point[] mPointRadii;
   1.195 +    private Rect mRect;
   1.196 +    private double mX;
   1.197 +    private double mY;
   1.198 +    private double mZ;
   1.199 +
   1.200 +    private int mMetaState;
   1.201 +    private int mFlags;
   1.202 +    private int mKeyCode;
   1.203 +    private int mUnicodeChar;
   1.204 +    private int mBaseUnicodeChar; // mUnicodeChar without meta states applied
   1.205 +    private int mDOMPrintableKeyValue;
   1.206 +    private int mRepeatCount;
   1.207 +    private int mCount;
   1.208 +    private int mStart;
   1.209 +    private int mEnd;
   1.210 +    private String mCharacters;
   1.211 +    private String mCharactersExtra;
   1.212 +    private String mData;
   1.213 +    private int mRangeType;
   1.214 +    private int mRangeStyles;
   1.215 +    private int mRangeLineStyle;
   1.216 +    private boolean mRangeBoldLine;
   1.217 +    private int mRangeForeColor;
   1.218 +    private int mRangeBackColor;
   1.219 +    private int mRangeLineColor;
   1.220 +    private Location mLocation;
   1.221 +    private Address mAddress;
   1.222 +    private DomKeyLocation mDomKeyLocation;
   1.223 +
   1.224 +    private int     mConnectionType;
   1.225 +    private boolean mIsWifi;
   1.226 +    private int     mDHCPGateway;
   1.227 +
   1.228 +    private int mNativeWindow;
   1.229 +
   1.230 +    private short mScreenOrientation;
   1.231 +
   1.232 +    private ByteBuffer mBuffer;
   1.233 +
   1.234 +    private int mWidth;
   1.235 +    private int mHeight;
   1.236 +
   1.237 +    private String[] mPrefNames;
   1.238 +
   1.239 +    private GeckoEvent(NativeGeckoEvent event) {
   1.240 +        mType = event.value;
   1.241 +    }
   1.242 +
   1.243 +    public static GeckoEvent createAppBackgroundingEvent() {
   1.244 +        return GeckoEvent.get(NativeGeckoEvent.APP_BACKGROUNDING);
   1.245 +    }
   1.246 +
   1.247 +    public static GeckoEvent createAppForegroundingEvent() {
   1.248 +        return GeckoEvent.get(NativeGeckoEvent.APP_FOREGROUNDING);
   1.249 +    }
   1.250 +
   1.251 +    public static GeckoEvent createNoOpEvent() {
   1.252 +        return GeckoEvent.get(NativeGeckoEvent.NOOP);
   1.253 +    }
   1.254 +
   1.255 +    public static GeckoEvent createKeyEvent(KeyEvent k, int metaState) {
   1.256 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.KEY_EVENT);
   1.257 +        event.initKeyEvent(k, metaState);
   1.258 +        return event;
   1.259 +    }
   1.260 +
   1.261 +    public static GeckoEvent createCompositorCreateEvent(int width, int height) {
   1.262 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.COMPOSITOR_CREATE);
   1.263 +        event.mWidth = width;
   1.264 +        event.mHeight = height;
   1.265 +        return event;
   1.266 +    }
   1.267 +
   1.268 +    public static GeckoEvent createCompositorPauseEvent() {
   1.269 +        return GeckoEvent.get(NativeGeckoEvent.COMPOSITOR_PAUSE);
   1.270 +    }
   1.271 +
   1.272 +    public static GeckoEvent createCompositorResumeEvent() {
   1.273 +        return GeckoEvent.get(NativeGeckoEvent.COMPOSITOR_RESUME);
   1.274 +    }
   1.275 +
   1.276 +    private void initKeyEvent(KeyEvent k, int metaState) {
   1.277 +        mAction = k.getAction();
   1.278 +        mTime = k.getEventTime();
   1.279 +        // Normally we expect k.getMetaState() to reflect the current meta-state; however,
   1.280 +        // some software-generated key events may not have k.getMetaState() set, e.g. key
   1.281 +        // events from Swype. Therefore, it's necessary to combine the key's meta-states
   1.282 +        // with the meta-states that we keep separately in KeyListener
   1.283 +        mMetaState = k.getMetaState() | metaState;
   1.284 +        mFlags = k.getFlags();
   1.285 +        mKeyCode = k.getKeyCode();
   1.286 +        mUnicodeChar = k.getUnicodeChar(mMetaState);
   1.287 +        // e.g. for Ctrl+A, Android returns 0 for mUnicodeChar,
   1.288 +        // but Gecko expects 'a', so we return that in mBaseUnicodeChar
   1.289 +        mBaseUnicodeChar = k.getUnicodeChar(0);
   1.290 +        mRepeatCount = k.getRepeatCount();
   1.291 +        mCharacters = k.getCharacters();
   1.292 +        if (mUnicodeChar >= ' ') {
   1.293 +            mDOMPrintableKeyValue = mUnicodeChar;
   1.294 +        } else {
   1.295 +            int unmodifiedMetaState =
   1.296 +                mMetaState & ~(KeyEvent.META_ALT_MASK |
   1.297 +                               KeyEvent.META_CTRL_MASK |
   1.298 +                               KeyEvent.META_META_MASK);
   1.299 +            if (unmodifiedMetaState != mMetaState) {
   1.300 +                mDOMPrintableKeyValue = k.getUnicodeChar(unmodifiedMetaState);
   1.301 +            }
   1.302 +        }
   1.303 +        mDomKeyLocation = isJoystickButton(mKeyCode) ? DomKeyLocation.DOM_KEY_LOCATION_JOYSTICK
   1.304 +                                                     : DomKeyLocation.DOM_KEY_LOCATION_MOBILE;
   1.305 +    }
   1.306 +
   1.307 +    /**
   1.308 +     * This method tests if a key is one of the described in:
   1.309 +     * https://bugzilla.mozilla.org/show_bug.cgi?id=756504#c0
   1.310 +     * @param keyCode int with the key code (Android key constant from KeyEvent)
   1.311 +     * @return true if the key is one of the listed above, false otherwise.
   1.312 +     */
   1.313 +    private static boolean isJoystickButton(int keyCode) {
   1.314 +        switch (keyCode) {
   1.315 +            case KeyEvent.KEYCODE_DPAD_CENTER:
   1.316 +            case KeyEvent.KEYCODE_DPAD_LEFT:
   1.317 +            case KeyEvent.KEYCODE_DPAD_RIGHT:
   1.318 +            case KeyEvent.KEYCODE_DPAD_DOWN:
   1.319 +            case KeyEvent.KEYCODE_DPAD_UP:
   1.320 +                return true;
   1.321 +            default:
   1.322 +                if (Build.VERSION.SDK_INT >= 12) {
   1.323 +                    return KeyEvent.isGamepadButton(keyCode);
   1.324 +                }
   1.325 +                return GeckoEvent.isGamepadButton(keyCode);
   1.326 +        }
   1.327 +    }
   1.328 +
   1.329 +    /**
   1.330 +     * This method is a replacement for the the KeyEvent.isGamepadButton method to be
   1.331 +     * compatible with Build.VERSION.SDK_INT < 12. This is an implementantion of the
   1.332 +     * same method isGamepadButton available after SDK 12.
   1.333 +     * @param keyCode int with the key code (Android key constant from KeyEvent).
   1.334 +     * @return True if the keycode is a gamepad button, such as {@link #KEYCODE_BUTTON_A}.
   1.335 +     */
   1.336 +    private static boolean isGamepadButton(int keyCode) {
   1.337 +        switch (keyCode) {
   1.338 +            case KeyEvent.KEYCODE_BUTTON_A:
   1.339 +            case KeyEvent.KEYCODE_BUTTON_B:
   1.340 +            case KeyEvent.KEYCODE_BUTTON_C:
   1.341 +            case KeyEvent.KEYCODE_BUTTON_X:
   1.342 +            case KeyEvent.KEYCODE_BUTTON_Y:
   1.343 +            case KeyEvent.KEYCODE_BUTTON_Z:
   1.344 +            case KeyEvent.KEYCODE_BUTTON_L1:
   1.345 +            case KeyEvent.KEYCODE_BUTTON_R1:
   1.346 +            case KeyEvent.KEYCODE_BUTTON_L2:
   1.347 +            case KeyEvent.KEYCODE_BUTTON_R2:
   1.348 +            case KeyEvent.KEYCODE_BUTTON_THUMBL:
   1.349 +            case KeyEvent.KEYCODE_BUTTON_THUMBR:
   1.350 +            case KeyEvent.KEYCODE_BUTTON_START:
   1.351 +            case KeyEvent.KEYCODE_BUTTON_SELECT:
   1.352 +            case KeyEvent.KEYCODE_BUTTON_MODE:
   1.353 +            case KeyEvent.KEYCODE_BUTTON_1:
   1.354 +            case KeyEvent.KEYCODE_BUTTON_2:
   1.355 +            case KeyEvent.KEYCODE_BUTTON_3:
   1.356 +            case KeyEvent.KEYCODE_BUTTON_4:
   1.357 +            case KeyEvent.KEYCODE_BUTTON_5:
   1.358 +            case KeyEvent.KEYCODE_BUTTON_6:
   1.359 +            case KeyEvent.KEYCODE_BUTTON_7:
   1.360 +            case KeyEvent.KEYCODE_BUTTON_8:
   1.361 +            case KeyEvent.KEYCODE_BUTTON_9:
   1.362 +            case KeyEvent.KEYCODE_BUTTON_10:
   1.363 +            case KeyEvent.KEYCODE_BUTTON_11:
   1.364 +            case KeyEvent.KEYCODE_BUTTON_12:
   1.365 +            case KeyEvent.KEYCODE_BUTTON_13:
   1.366 +            case KeyEvent.KEYCODE_BUTTON_14:
   1.367 +            case KeyEvent.KEYCODE_BUTTON_15:
   1.368 +            case KeyEvent.KEYCODE_BUTTON_16:
   1.369 +                return true;
   1.370 +            default:
   1.371 +                return false;
   1.372 +        }
   1.373 +    }
   1.374 +
   1.375 +    public static GeckoEvent createNativeGestureEvent(int action, PointF pt, double size) {
   1.376 +        try {
   1.377 +            GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.NATIVE_GESTURE_EVENT);
   1.378 +            event.mAction = action;
   1.379 +            event.mCount = 1;
   1.380 +            event.mPoints = new Point[1];
   1.381 +
   1.382 +            PointF geckoPoint = new PointF(pt.x, pt.y);
   1.383 +            geckoPoint = GeckoAppShell.getLayerView().convertViewPointToLayerPoint(geckoPoint);
   1.384 +
   1.385 +            if (geckoPoint == null) {
   1.386 +                // This could happen if Gecko isn't ready yet.
   1.387 +                return null;
   1.388 +            }
   1.389 +
   1.390 +            event.mPoints[0] = new Point(Math.round(geckoPoint.x), Math.round(geckoPoint.y));
   1.391 +
   1.392 +            event.mX = size;
   1.393 +            event.mTime = System.currentTimeMillis();
   1.394 +            return event;
   1.395 +        } catch (Exception e) {
   1.396 +            // This can happen if Gecko isn't ready yet
   1.397 +            return null;
   1.398 +        }
   1.399 +    }
   1.400 +
   1.401 +    /**
   1.402 +     * Creates a GeckoEvent that contains the data from the MotionEvent.
   1.403 +     * The keepInViewCoordinates parameter can be set to false to convert from the Java
   1.404 +     * coordinate system (device pixels relative to the LayerView) to a coordinate system
   1.405 +     * relative to gecko's coordinate system (CSS pixels relative to gecko scroll position).
   1.406 +     */
   1.407 +    public static GeckoEvent createMotionEvent(MotionEvent m, boolean keepInViewCoordinates) {
   1.408 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.MOTION_EVENT);
   1.409 +        event.initMotionEvent(m, keepInViewCoordinates);
   1.410 +        return event;
   1.411 +    }
   1.412 +
   1.413 +    private void initMotionEvent(MotionEvent m, boolean keepInViewCoordinates) {
   1.414 +        mAction = m.getActionMasked();
   1.415 +        mTime = (System.currentTimeMillis() - SystemClock.elapsedRealtime()) + m.getEventTime();
   1.416 +        mMetaState = m.getMetaState();
   1.417 +
   1.418 +        switch (mAction) {
   1.419 +            case MotionEvent.ACTION_CANCEL:
   1.420 +            case MotionEvent.ACTION_UP:
   1.421 +            case MotionEvent.ACTION_POINTER_UP:
   1.422 +            case MotionEvent.ACTION_POINTER_DOWN:
   1.423 +            case MotionEvent.ACTION_DOWN:
   1.424 +            case MotionEvent.ACTION_MOVE:
   1.425 +            case MotionEvent.ACTION_HOVER_ENTER:
   1.426 +            case MotionEvent.ACTION_HOVER_MOVE:
   1.427 +            case MotionEvent.ACTION_HOVER_EXIT: {
   1.428 +                mCount = m.getPointerCount();
   1.429 +                mPoints = new Point[mCount];
   1.430 +                mPointIndicies = new int[mCount];
   1.431 +                mOrientations = new float[mCount];
   1.432 +                mPressures = new float[mCount];
   1.433 +                mPointRadii = new Point[mCount];
   1.434 +                mPointerIndex = m.getActionIndex();
   1.435 +                for (int i = 0; i < mCount; i++) {
   1.436 +                    addMotionPoint(i, i, m, keepInViewCoordinates);
   1.437 +                }
   1.438 +                break;
   1.439 +            }
   1.440 +            default: {
   1.441 +                mCount = 0;
   1.442 +                mPointerIndex = -1;
   1.443 +                mPoints = new Point[mCount];
   1.444 +                mPointIndicies = new int[mCount];
   1.445 +                mOrientations = new float[mCount];
   1.446 +                mPressures = new float[mCount];
   1.447 +                mPointRadii = new Point[mCount];
   1.448 +            }
   1.449 +        }
   1.450 +    }
   1.451 +
   1.452 +    private void addMotionPoint(int index, int eventIndex, MotionEvent event, boolean keepInViewCoordinates) {
   1.453 +        try {
   1.454 +            PointF geckoPoint = new PointF(event.getX(eventIndex), event.getY(eventIndex));
   1.455 +            if (!keepInViewCoordinates) {
   1.456 +                geckoPoint = GeckoAppShell.getLayerView().convertViewPointToLayerPoint(geckoPoint);
   1.457 +            }
   1.458 +
   1.459 +            mPoints[index] = new Point(Math.round(geckoPoint.x), Math.round(geckoPoint.y));
   1.460 +            mPointIndicies[index] = event.getPointerId(eventIndex);
   1.461 +            // getToolMajor, getToolMinor and getOrientation are API Level 9 features
   1.462 +            if (Build.VERSION.SDK_INT >= 9) {
   1.463 +                double radians = event.getOrientation(eventIndex);
   1.464 +                mOrientations[index] = (float) Math.toDegrees(radians);
   1.465 +                // w3c touchevents spec does not allow orientations == 90
   1.466 +                // this shifts it to -90, which will be shifted to zero below
   1.467 +                if (mOrientations[index] == 90)
   1.468 +                    mOrientations[index] = -90;
   1.469 +
   1.470 +                // w3c touchevent radius are given by an orientation between 0 and 90
   1.471 +                // the radius is found by removing the orientation and measuring the x and y
   1.472 +                // radius of the resulting ellipse
   1.473 +                // for android orientations >= 0 and < 90, the major axis should correspond to
   1.474 +                // just reporting the y radius as the major one, and x as minor
   1.475 +                // however, for a radius < 0, we have to shift the orientation by adding 90, and
   1.476 +                // reverse which radius is major and minor
   1.477 +                if (mOrientations[index] < 0) {
   1.478 +                    mOrientations[index] += 90;
   1.479 +                    mPointRadii[index] = new Point((int)event.getToolMajor(eventIndex)/2,
   1.480 +                                                   (int)event.getToolMinor(eventIndex)/2);
   1.481 +                } else {
   1.482 +                    mPointRadii[index] = new Point((int)event.getToolMinor(eventIndex)/2,
   1.483 +                                                   (int)event.getToolMajor(eventIndex)/2);
   1.484 +                }
   1.485 +            } else {
   1.486 +                float size = event.getSize(eventIndex);
   1.487 +                Resources resources = GeckoAppShell.getContext().getResources();
   1.488 +                DisplayMetrics displaymetrics = resources.getDisplayMetrics();
   1.489 +                size = size*Math.min(displaymetrics.heightPixels, displaymetrics.widthPixels);
   1.490 +                mPointRadii[index] = new Point((int)size,(int)size);
   1.491 +                mOrientations[index] = 0;
   1.492 +            }
   1.493 +            if (!keepInViewCoordinates) {
   1.494 +                // If we are converting to gecko CSS pixels, then we should adjust the
   1.495 +                // radii as well
   1.496 +                float zoom = GeckoAppShell.getLayerView().getViewportMetrics().zoomFactor;
   1.497 +                mPointRadii[index].x /= zoom;
   1.498 +                mPointRadii[index].y /= zoom;
   1.499 +            }
   1.500 +            mPressures[index] = event.getPressure(eventIndex);
   1.501 +        } catch (Exception ex) {
   1.502 +            Log.e(LOGTAG, "Error creating motion point " + index, ex);
   1.503 +            mPointRadii[index] = new Point(0, 0);
   1.504 +            mPoints[index] = new Point(0, 0);
   1.505 +        }
   1.506 +    }
   1.507 +
   1.508 +    private static int HalSensorAccuracyFor(int androidAccuracy) {
   1.509 +        switch (androidAccuracy) {
   1.510 +        case SensorManager.SENSOR_STATUS_UNRELIABLE:
   1.511 +            return GeckoHalDefines.SENSOR_ACCURACY_UNRELIABLE;
   1.512 +        case SensorManager.SENSOR_STATUS_ACCURACY_LOW:
   1.513 +            return GeckoHalDefines.SENSOR_ACCURACY_LOW;
   1.514 +        case SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM:
   1.515 +            return GeckoHalDefines.SENSOR_ACCURACY_MED;
   1.516 +        case SensorManager.SENSOR_STATUS_ACCURACY_HIGH:
   1.517 +            return GeckoHalDefines.SENSOR_ACCURACY_HIGH;
   1.518 +        }
   1.519 +        return GeckoHalDefines.SENSOR_ACCURACY_UNKNOWN;
   1.520 +    }
   1.521 +
   1.522 +    public static GeckoEvent createSensorEvent(SensorEvent s) {
   1.523 +        int sensor_type = s.sensor.getType();
   1.524 +        GeckoEvent event = null;
   1.525 +
   1.526 +        switch(sensor_type) {
   1.527 +
   1.528 +        case Sensor.TYPE_ACCELEROMETER:
   1.529 +            event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT);
   1.530 +            event.mFlags = GeckoHalDefines.SENSOR_ACCELERATION;
   1.531 +            event.mMetaState = HalSensorAccuracyFor(s.accuracy);
   1.532 +            event.mX = s.values[0];
   1.533 +            event.mY = s.values[1];
   1.534 +            event.mZ = s.values[2];
   1.535 +            break;
   1.536 +
   1.537 +        case 10 /* Requires API Level 9, so just use the raw value - Sensor.TYPE_LINEAR_ACCELEROMETER*/ :
   1.538 +            event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT);
   1.539 +            event.mFlags = GeckoHalDefines.SENSOR_LINEAR_ACCELERATION;
   1.540 +            event.mMetaState = HalSensorAccuracyFor(s.accuracy);
   1.541 +            event.mX = s.values[0];
   1.542 +            event.mY = s.values[1];
   1.543 +            event.mZ = s.values[2];
   1.544 +            break;
   1.545 +
   1.546 +        case Sensor.TYPE_ORIENTATION:
   1.547 +            event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT);
   1.548 +            event.mFlags = GeckoHalDefines.SENSOR_ORIENTATION;
   1.549 +            event.mMetaState = HalSensorAccuracyFor(s.accuracy);
   1.550 +            event.mX = s.values[0];
   1.551 +            event.mY = s.values[1];
   1.552 +            event.mZ = s.values[2];
   1.553 +            break;
   1.554 +
   1.555 +        case Sensor.TYPE_GYROSCOPE:
   1.556 +            event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT);
   1.557 +            event.mFlags = GeckoHalDefines.SENSOR_GYROSCOPE;
   1.558 +            event.mMetaState = HalSensorAccuracyFor(s.accuracy);
   1.559 +            event.mX = Math.toDegrees(s.values[0]);
   1.560 +            event.mY = Math.toDegrees(s.values[1]);
   1.561 +            event.mZ = Math.toDegrees(s.values[2]);
   1.562 +            break;
   1.563 +
   1.564 +        case Sensor.TYPE_PROXIMITY:
   1.565 +            event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT);
   1.566 +            event.mFlags = GeckoHalDefines.SENSOR_PROXIMITY;
   1.567 +            event.mMetaState = HalSensorAccuracyFor(s.accuracy);
   1.568 +            event.mX = s.values[0];
   1.569 +            event.mY = 0;
   1.570 +            event.mZ = s.sensor.getMaximumRange();
   1.571 +            break;
   1.572 +
   1.573 +        case Sensor.TYPE_LIGHT:
   1.574 +            event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT);
   1.575 +            event.mFlags = GeckoHalDefines.SENSOR_LIGHT;
   1.576 +            event.mMetaState = HalSensorAccuracyFor(s.accuracy);
   1.577 +            event.mX = s.values[0];
   1.578 +            break;
   1.579 +        }
   1.580 +        return event;
   1.581 +    }
   1.582 +
   1.583 +    public static GeckoEvent createLocationEvent(Location l) {
   1.584 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOCATION_EVENT);
   1.585 +        event.mLocation = l;
   1.586 +        return event;
   1.587 +    }
   1.588 +
   1.589 +    public static GeckoEvent createIMEEvent(ImeAction action) {
   1.590 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT);
   1.591 +        event.mAction = action.value;
   1.592 +        return event;
   1.593 +    }
   1.594 +
   1.595 +    public static GeckoEvent createIMEKeyEvent(KeyEvent k) {
   1.596 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_KEY_EVENT);
   1.597 +        event.initKeyEvent(k, 0);
   1.598 +        return event;
   1.599 +    }
   1.600 +
   1.601 +    public static GeckoEvent createIMEReplaceEvent(int start, int end,
   1.602 +                                                   String text) {
   1.603 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT);
   1.604 +        event.mAction = ImeAction.IME_REPLACE_TEXT.value;
   1.605 +        event.mStart = start;
   1.606 +        event.mEnd = end;
   1.607 +        event.mCharacters = text;
   1.608 +        return event;
   1.609 +    }
   1.610 +
   1.611 +    public static GeckoEvent createIMESelectEvent(int start, int end) {
   1.612 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT);
   1.613 +        event.mAction = ImeAction.IME_SET_SELECTION.value;
   1.614 +        event.mStart = start;
   1.615 +        event.mEnd = end;
   1.616 +        return event;
   1.617 +    }
   1.618 +
   1.619 +    public static GeckoEvent createIMECompositionEvent(int start, int end) {
   1.620 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT);
   1.621 +        event.mAction = ImeAction.IME_UPDATE_COMPOSITION.value;
   1.622 +        event.mStart = start;
   1.623 +        event.mEnd = end;
   1.624 +        return event;
   1.625 +    }
   1.626 +
   1.627 +    public static GeckoEvent createIMERangeEvent(int start,
   1.628 +                                                 int end, int rangeType,
   1.629 +                                                 int rangeStyles,
   1.630 +                                                 int rangeLineStyle,
   1.631 +                                                 boolean rangeBoldLine,
   1.632 +                                                 int rangeForeColor,
   1.633 +                                                 int rangeBackColor,
   1.634 +                                                 int rangeLineColor) {
   1.635 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT);
   1.636 +        event.mAction = ImeAction.IME_ADD_COMPOSITION_RANGE.value;
   1.637 +        event.mStart = start;
   1.638 +        event.mEnd = end;
   1.639 +        event.mRangeType = rangeType;
   1.640 +        event.mRangeStyles = rangeStyles;
   1.641 +        event.mRangeLineStyle = rangeLineStyle;
   1.642 +        event.mRangeBoldLine = rangeBoldLine;
   1.643 +        event.mRangeForeColor = rangeForeColor;
   1.644 +        event.mRangeBackColor = rangeBackColor;
   1.645 +        event.mRangeLineColor = rangeLineColor;
   1.646 +        return event;
   1.647 +    }
   1.648 +
   1.649 +    public static GeckoEvent createDrawEvent(Rect rect) {
   1.650 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.DRAW);
   1.651 +        event.mRect = rect;
   1.652 +        return event;
   1.653 +    }
   1.654 +
   1.655 +    public static GeckoEvent createSizeChangedEvent(int w, int h, int screenw, int screenh) {
   1.656 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.SIZE_CHANGED);
   1.657 +        event.mPoints = new Point[2];
   1.658 +        event.mPoints[0] = new Point(w, h);
   1.659 +        event.mPoints[1] = new Point(screenw, screenh);
   1.660 +        return event;
   1.661 +    }
   1.662 +
   1.663 +    @RobocopTarget
   1.664 +    public static GeckoEvent createBroadcastEvent(String subject, String data) {
   1.665 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.BROADCAST);
   1.666 +        event.mCharacters = subject;
   1.667 +        event.mCharactersExtra = data;
   1.668 +        return event;
   1.669 +    }
   1.670 +
   1.671 +    public static GeckoEvent createViewportEvent(ImmutableViewportMetrics metrics, DisplayPortMetrics displayPort) {
   1.672 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.VIEWPORT);
   1.673 +        event.mCharacters = "Viewport:Change";
   1.674 +        StringBuilder sb = new StringBuilder(256);
   1.675 +        sb.append("{ \"x\" : ").append(metrics.viewportRectLeft)
   1.676 +          .append(", \"y\" : ").append(metrics.viewportRectTop)
   1.677 +          .append(", \"zoom\" : ").append(metrics.zoomFactor)
   1.678 +          .append(", \"fixedMarginLeft\" : ").append(metrics.marginLeft)
   1.679 +          .append(", \"fixedMarginTop\" : ").append(metrics.marginTop)
   1.680 +          .append(", \"fixedMarginRight\" : ").append(metrics.marginRight)
   1.681 +          .append(", \"fixedMarginBottom\" : ").append(metrics.marginBottom)
   1.682 +          .append(", \"displayPort\" :").append(displayPort.toJSON())
   1.683 +          .append('}');
   1.684 +        event.mCharactersExtra = sb.toString();
   1.685 +        return event;
   1.686 +    }
   1.687 +
   1.688 +    public static GeckoEvent createURILoadEvent(String uri) {
   1.689 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOAD_URI);
   1.690 +        event.mCharacters = uri;
   1.691 +        event.mCharactersExtra = "";
   1.692 +        return event;
   1.693 +    }
   1.694 +
   1.695 +    public static GeckoEvent createWebappLoadEvent(String uri) {
   1.696 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOAD_URI);
   1.697 +        event.mCharacters = uri;
   1.698 +        event.mCharactersExtra = "-webapp";
   1.699 +        return event;
   1.700 +    }
   1.701 +
   1.702 +    public static GeckoEvent createBookmarkLoadEvent(String uri) {
   1.703 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOAD_URI);
   1.704 +        event.mCharacters = uri;
   1.705 +        event.mCharactersExtra = "-bookmark";
   1.706 +        return event;
   1.707 +    }
   1.708 +
   1.709 +    public static GeckoEvent createVisitedEvent(String data) {
   1.710 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.VISITED);
   1.711 +        event.mCharacters = data;
   1.712 +        return event;
   1.713 +    }
   1.714 +
   1.715 +    public static GeckoEvent createNetworkEvent(int connectionType, boolean isWifi, int DHCPGateway) {
   1.716 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.NETWORK_CHANGED);
   1.717 +        event.mConnectionType = connectionType;
   1.718 +        event.mIsWifi = isWifi;
   1.719 +        event.mDHCPGateway = DHCPGateway;
   1.720 +        return event;
   1.721 +    }
   1.722 +
   1.723 +    public static GeckoEvent createThumbnailEvent(int tabId, int bufw, int bufh, ByteBuffer buffer) {
   1.724 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.THUMBNAIL);
   1.725 +        event.mPoints = new Point[1];
   1.726 +        event.mPoints[0] = new Point(bufw, bufh);
   1.727 +        event.mMetaState = tabId;
   1.728 +        event.mBuffer = buffer;
   1.729 +        return event;
   1.730 +    }
   1.731 +
   1.732 +    public static GeckoEvent createScreenOrientationEvent(short aScreenOrientation) {
   1.733 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.SCREENORIENTATION_CHANGED);
   1.734 +        event.mScreenOrientation = aScreenOrientation;
   1.735 +        return event;
   1.736 +    }
   1.737 +
   1.738 +    public static GeckoEvent createCallObserverEvent(String observerKey, String topic, String data) {
   1.739 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.CALL_OBSERVER);
   1.740 +        event.mCharacters = observerKey;
   1.741 +        event.mCharactersExtra = topic;
   1.742 +        event.mData = data;
   1.743 +        return event;
   1.744 +    }
   1.745 +
   1.746 +    public static GeckoEvent createRemoveObserverEvent(String observerKey) {
   1.747 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.REMOVE_OBSERVER);
   1.748 +        event.mCharacters = observerKey;
   1.749 +        return event;
   1.750 +    }
   1.751 +
   1.752 +    @RobocopTarget
   1.753 +    public static GeckoEvent createPreferencesObserveEvent(int requestId, String[] prefNames) {
   1.754 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.PREFERENCES_OBSERVE);
   1.755 +        event.mCount = requestId;
   1.756 +        event.mPrefNames = prefNames;
   1.757 +        return event;
   1.758 +    }
   1.759 +
   1.760 +    @RobocopTarget
   1.761 +    public static GeckoEvent createPreferencesGetEvent(int requestId, String[] prefNames) {
   1.762 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.PREFERENCES_GET);
   1.763 +        event.mCount = requestId;
   1.764 +        event.mPrefNames = prefNames;
   1.765 +        return event;
   1.766 +    }
   1.767 +
   1.768 +    @RobocopTarget
   1.769 +    public static GeckoEvent createPreferencesRemoveObserversEvent(int requestId) {
   1.770 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.PREFERENCES_REMOVE_OBSERVERS);
   1.771 +        event.mCount = requestId;
   1.772 +        return event;
   1.773 +    }
   1.774 +
   1.775 +    public static GeckoEvent createLowMemoryEvent(int level) {
   1.776 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOW_MEMORY);
   1.777 +        event.mMetaState = level;
   1.778 +        return event;
   1.779 +    }
   1.780 +
   1.781 +    public static GeckoEvent createNetworkLinkChangeEvent(String status) {
   1.782 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.NETWORK_LINK_CHANGE);
   1.783 +        event.mCharacters = status;
   1.784 +        return event;
   1.785 +    }
   1.786 +
   1.787 +    public static GeckoEvent createTelemetryHistogramAddEvent(String histogram,
   1.788 +                                                              int value) {
   1.789 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.TELEMETRY_HISTOGRAM_ADD);
   1.790 +        event.mCharacters = histogram;
   1.791 +        event.mCount = value;
   1.792 +        return event;
   1.793 +    }
   1.794 +
   1.795 +    public static GeckoEvent createTelemetryUISessionStartEvent(String session, long timestamp) {
   1.796 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.TELEMETRY_UI_SESSION_START);
   1.797 +        event.mCharacters = session;
   1.798 +        event.mTime = timestamp;
   1.799 +        return event;
   1.800 +    }
   1.801 +
   1.802 +    public static GeckoEvent createTelemetryUISessionStopEvent(String session, String reason, long timestamp) {
   1.803 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.TELEMETRY_UI_SESSION_STOP);
   1.804 +        event.mCharacters = session;
   1.805 +        event.mCharactersExtra = reason;
   1.806 +        event.mTime = timestamp;
   1.807 +        return event;
   1.808 +    }
   1.809 +
   1.810 +    public static GeckoEvent createTelemetryUIEvent(String action, String method, long timestamp, String extras) {
   1.811 +        GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.TELEMETRY_UI_EVENT);
   1.812 +        event.mData = action;
   1.813 +        event.mCharacters = method;
   1.814 +        event.mCharactersExtra = extras;
   1.815 +        event.mTime = timestamp;
   1.816 +        return event;
   1.817 +    }
   1.818 +
   1.819 +    public void setAckNeeded(boolean ackNeeded) {
   1.820 +        mAckNeeded = ackNeeded;
   1.821 +    }
   1.822 +}

mercurial