michael@0: /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko; michael@0: michael@0: import org.mozilla.gecko.gfx.DisplayPortMetrics; michael@0: import org.mozilla.gecko.gfx.ImmutableViewportMetrics; michael@0: import org.mozilla.gecko.mozglue.JNITarget; michael@0: import org.mozilla.gecko.mozglue.generatorannotations.GeneratorOptions; michael@0: import org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI; michael@0: import org.mozilla.gecko.mozglue.RobocopTarget; michael@0: michael@0: import android.content.res.Resources; michael@0: import android.graphics.Point; michael@0: import android.graphics.PointF; michael@0: import android.graphics.Rect; michael@0: import android.hardware.Sensor; michael@0: import android.hardware.SensorEvent; michael@0: import android.hardware.SensorManager; michael@0: import android.location.Address; michael@0: import android.location.Location; michael@0: import android.os.Build; michael@0: import android.os.SystemClock; michael@0: import android.util.DisplayMetrics; michael@0: import android.util.Log; michael@0: import android.util.SparseArray; michael@0: import android.view.KeyEvent; michael@0: import android.view.MotionEvent; michael@0: michael@0: import java.nio.ByteBuffer; michael@0: import java.util.concurrent.ArrayBlockingQueue; michael@0: michael@0: /* We're not allowed to hold on to most events given to us michael@0: * so we save the parts of the events we want to use in GeckoEvent. michael@0: * Fields have different meanings depending on the event type. michael@0: */ michael@0: michael@0: /* This class is referenced by Robocop via reflection; use care when michael@0: * modifying the signature. michael@0: */ michael@0: @JNITarget michael@0: public class GeckoEvent { michael@0: private static final String LOGTAG = "GeckoEvent"; michael@0: michael@0: private static final int EVENT_FACTORY_SIZE = 5; michael@0: michael@0: // Maybe we're probably better to just make mType non final, and just store GeckoEvents in here... michael@0: private static SparseArray> mEvents = new SparseArray>(); michael@0: michael@0: public static GeckoEvent get(NativeGeckoEvent type) { michael@0: synchronized (mEvents) { michael@0: ArrayBlockingQueue events = mEvents.get(type.value); michael@0: if (events != null && events.size() > 0) { michael@0: return events.poll(); michael@0: } michael@0: } michael@0: michael@0: return new GeckoEvent(type); michael@0: } michael@0: michael@0: public void recycle() { michael@0: synchronized (mEvents) { michael@0: ArrayBlockingQueue events = mEvents.get(mType); michael@0: if (events == null) { michael@0: events = new ArrayBlockingQueue(EVENT_FACTORY_SIZE); michael@0: mEvents.put(mType, events); michael@0: } michael@0: michael@0: events.offer(this); michael@0: } michael@0: } michael@0: michael@0: // Make sure to keep these values in sync with the enum in michael@0: // AndroidGeckoEvent in widget/android/AndroidJavaWrappers.h michael@0: @JNITarget michael@0: private enum NativeGeckoEvent { michael@0: NATIVE_POKE(0), michael@0: KEY_EVENT(1), michael@0: MOTION_EVENT(2), michael@0: SENSOR_EVENT(3), michael@0: LOCATION_EVENT(5), michael@0: IME_EVENT(6), michael@0: DRAW(7), michael@0: SIZE_CHANGED(8), michael@0: APP_BACKGROUNDING(9), michael@0: APP_FOREGROUNDING(10), michael@0: LOAD_URI(12), michael@0: NOOP(15), michael@0: BROADCAST(19), michael@0: VIEWPORT(20), michael@0: VISITED(21), michael@0: NETWORK_CHANGED(22), michael@0: THUMBNAIL(25), michael@0: SCREENORIENTATION_CHANGED(27), michael@0: COMPOSITOR_CREATE(28), michael@0: COMPOSITOR_PAUSE(29), michael@0: COMPOSITOR_RESUME(30), michael@0: NATIVE_GESTURE_EVENT(31), michael@0: IME_KEY_EVENT(32), michael@0: CALL_OBSERVER(33), michael@0: REMOVE_OBSERVER(34), michael@0: LOW_MEMORY(35), michael@0: NETWORK_LINK_CHANGE(36), michael@0: TELEMETRY_HISTOGRAM_ADD(37), michael@0: PREFERENCES_OBSERVE(39), michael@0: PREFERENCES_GET(40), michael@0: PREFERENCES_REMOVE_OBSERVERS(41), michael@0: TELEMETRY_UI_SESSION_START(42), michael@0: TELEMETRY_UI_SESSION_STOP(43), michael@0: TELEMETRY_UI_EVENT(44); michael@0: michael@0: public final int value; michael@0: michael@0: private NativeGeckoEvent(int value) { michael@0: this.value = value; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * The DomKeyLocation enum encapsulates the DOM KeyboardEvent's constants. michael@0: * @see https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Key_location_constants michael@0: */ michael@0: @GeneratorOptions(generatedClassName = "JavaDomKeyLocation") michael@0: @WrapEntireClassForJNI michael@0: public enum DomKeyLocation { michael@0: DOM_KEY_LOCATION_STANDARD(0), michael@0: DOM_KEY_LOCATION_LEFT(1), michael@0: DOM_KEY_LOCATION_RIGHT(2), michael@0: DOM_KEY_LOCATION_NUMPAD(3), michael@0: DOM_KEY_LOCATION_MOBILE(4), michael@0: DOM_KEY_LOCATION_JOYSTICK(5); michael@0: michael@0: public final int value; michael@0: michael@0: private DomKeyLocation(int value) { michael@0: this.value = value; michael@0: } michael@0: } michael@0: michael@0: // Encapsulation of common IME actions. michael@0: @JNITarget michael@0: public enum ImeAction { michael@0: IME_SYNCHRONIZE(0), michael@0: IME_REPLACE_TEXT(1), michael@0: IME_SET_SELECTION(2), michael@0: IME_ADD_COMPOSITION_RANGE(3), michael@0: IME_UPDATE_COMPOSITION(4), michael@0: IME_REMOVE_COMPOSITION(5), michael@0: IME_ACKNOWLEDGE_FOCUS(6); michael@0: michael@0: public final int value; michael@0: michael@0: private ImeAction(int value) { michael@0: this.value = value; michael@0: } michael@0: } michael@0: michael@0: public static final int IME_RANGE_CARETPOSITION = 1; michael@0: public static final int IME_RANGE_RAWINPUT = 2; michael@0: public static final int IME_RANGE_SELECTEDRAWTEXT = 3; michael@0: public static final int IME_RANGE_CONVERTEDTEXT = 4; michael@0: public static final int IME_RANGE_SELECTEDCONVERTEDTEXT = 5; michael@0: michael@0: public static final int IME_RANGE_LINE_NONE = 0; michael@0: public static final int IME_RANGE_LINE_DOTTED = 1; michael@0: public static final int IME_RANGE_LINE_DASHED = 2; michael@0: public static final int IME_RANGE_LINE_SOLID = 3; michael@0: public static final int IME_RANGE_LINE_DOUBLE = 4; michael@0: public static final int IME_RANGE_LINE_WAVY = 5; michael@0: michael@0: public static final int IME_RANGE_UNDERLINE = 1; michael@0: public static final int IME_RANGE_FORECOLOR = 2; michael@0: public static final int IME_RANGE_BACKCOLOR = 4; michael@0: public static final int IME_RANGE_LINECOLOR = 8; michael@0: michael@0: public static final int ACTION_MAGNIFY_START = 11; michael@0: public static final int ACTION_MAGNIFY = 12; michael@0: public static final int ACTION_MAGNIFY_END = 13; michael@0: michael@0: private final int mType; michael@0: private int mAction; michael@0: private boolean mAckNeeded; michael@0: private long mTime; michael@0: private Point[] mPoints; michael@0: private int[] mPointIndicies; michael@0: private int mPointerIndex; // index of the point that has changed michael@0: private float[] mOrientations; michael@0: private float[] mPressures; michael@0: private Point[] mPointRadii; michael@0: private Rect mRect; michael@0: private double mX; michael@0: private double mY; michael@0: private double mZ; michael@0: michael@0: private int mMetaState; michael@0: private int mFlags; michael@0: private int mKeyCode; michael@0: private int mUnicodeChar; michael@0: private int mBaseUnicodeChar; // mUnicodeChar without meta states applied michael@0: private int mDOMPrintableKeyValue; michael@0: private int mRepeatCount; michael@0: private int mCount; michael@0: private int mStart; michael@0: private int mEnd; michael@0: private String mCharacters; michael@0: private String mCharactersExtra; michael@0: private String mData; michael@0: private int mRangeType; michael@0: private int mRangeStyles; michael@0: private int mRangeLineStyle; michael@0: private boolean mRangeBoldLine; michael@0: private int mRangeForeColor; michael@0: private int mRangeBackColor; michael@0: private int mRangeLineColor; michael@0: private Location mLocation; michael@0: private Address mAddress; michael@0: private DomKeyLocation mDomKeyLocation; michael@0: michael@0: private int mConnectionType; michael@0: private boolean mIsWifi; michael@0: private int mDHCPGateway; michael@0: michael@0: private int mNativeWindow; michael@0: michael@0: private short mScreenOrientation; michael@0: michael@0: private ByteBuffer mBuffer; michael@0: michael@0: private int mWidth; michael@0: private int mHeight; michael@0: michael@0: private String[] mPrefNames; michael@0: michael@0: private GeckoEvent(NativeGeckoEvent event) { michael@0: mType = event.value; michael@0: } michael@0: michael@0: public static GeckoEvent createAppBackgroundingEvent() { michael@0: return GeckoEvent.get(NativeGeckoEvent.APP_BACKGROUNDING); michael@0: } michael@0: michael@0: public static GeckoEvent createAppForegroundingEvent() { michael@0: return GeckoEvent.get(NativeGeckoEvent.APP_FOREGROUNDING); michael@0: } michael@0: michael@0: public static GeckoEvent createNoOpEvent() { michael@0: return GeckoEvent.get(NativeGeckoEvent.NOOP); michael@0: } michael@0: michael@0: public static GeckoEvent createKeyEvent(KeyEvent k, int metaState) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.KEY_EVENT); michael@0: event.initKeyEvent(k, metaState); michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createCompositorCreateEvent(int width, int height) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.COMPOSITOR_CREATE); michael@0: event.mWidth = width; michael@0: event.mHeight = height; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createCompositorPauseEvent() { michael@0: return GeckoEvent.get(NativeGeckoEvent.COMPOSITOR_PAUSE); michael@0: } michael@0: michael@0: public static GeckoEvent createCompositorResumeEvent() { michael@0: return GeckoEvent.get(NativeGeckoEvent.COMPOSITOR_RESUME); michael@0: } michael@0: michael@0: private void initKeyEvent(KeyEvent k, int metaState) { michael@0: mAction = k.getAction(); michael@0: mTime = k.getEventTime(); michael@0: // Normally we expect k.getMetaState() to reflect the current meta-state; however, michael@0: // some software-generated key events may not have k.getMetaState() set, e.g. key michael@0: // events from Swype. Therefore, it's necessary to combine the key's meta-states michael@0: // with the meta-states that we keep separately in KeyListener michael@0: mMetaState = k.getMetaState() | metaState; michael@0: mFlags = k.getFlags(); michael@0: mKeyCode = k.getKeyCode(); michael@0: mUnicodeChar = k.getUnicodeChar(mMetaState); michael@0: // e.g. for Ctrl+A, Android returns 0 for mUnicodeChar, michael@0: // but Gecko expects 'a', so we return that in mBaseUnicodeChar michael@0: mBaseUnicodeChar = k.getUnicodeChar(0); michael@0: mRepeatCount = k.getRepeatCount(); michael@0: mCharacters = k.getCharacters(); michael@0: if (mUnicodeChar >= ' ') { michael@0: mDOMPrintableKeyValue = mUnicodeChar; michael@0: } else { michael@0: int unmodifiedMetaState = michael@0: mMetaState & ~(KeyEvent.META_ALT_MASK | michael@0: KeyEvent.META_CTRL_MASK | michael@0: KeyEvent.META_META_MASK); michael@0: if (unmodifiedMetaState != mMetaState) { michael@0: mDOMPrintableKeyValue = k.getUnicodeChar(unmodifiedMetaState); michael@0: } michael@0: } michael@0: mDomKeyLocation = isJoystickButton(mKeyCode) ? DomKeyLocation.DOM_KEY_LOCATION_JOYSTICK michael@0: : DomKeyLocation.DOM_KEY_LOCATION_MOBILE; michael@0: } michael@0: michael@0: /** michael@0: * This method tests if a key is one of the described in: michael@0: * https://bugzilla.mozilla.org/show_bug.cgi?id=756504#c0 michael@0: * @param keyCode int with the key code (Android key constant from KeyEvent) michael@0: * @return true if the key is one of the listed above, false otherwise. michael@0: */ michael@0: private static boolean isJoystickButton(int keyCode) { michael@0: switch (keyCode) { michael@0: case KeyEvent.KEYCODE_DPAD_CENTER: michael@0: case KeyEvent.KEYCODE_DPAD_LEFT: michael@0: case KeyEvent.KEYCODE_DPAD_RIGHT: michael@0: case KeyEvent.KEYCODE_DPAD_DOWN: michael@0: case KeyEvent.KEYCODE_DPAD_UP: michael@0: return true; michael@0: default: michael@0: if (Build.VERSION.SDK_INT >= 12) { michael@0: return KeyEvent.isGamepadButton(keyCode); michael@0: } michael@0: return GeckoEvent.isGamepadButton(keyCode); michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * This method is a replacement for the the KeyEvent.isGamepadButton method to be michael@0: * compatible with Build.VERSION.SDK_INT < 12. This is an implementantion of the michael@0: * same method isGamepadButton available after SDK 12. michael@0: * @param keyCode int with the key code (Android key constant from KeyEvent). michael@0: * @return True if the keycode is a gamepad button, such as {@link #KEYCODE_BUTTON_A}. michael@0: */ michael@0: private static boolean isGamepadButton(int keyCode) { michael@0: switch (keyCode) { michael@0: case KeyEvent.KEYCODE_BUTTON_A: michael@0: case KeyEvent.KEYCODE_BUTTON_B: michael@0: case KeyEvent.KEYCODE_BUTTON_C: michael@0: case KeyEvent.KEYCODE_BUTTON_X: michael@0: case KeyEvent.KEYCODE_BUTTON_Y: michael@0: case KeyEvent.KEYCODE_BUTTON_Z: michael@0: case KeyEvent.KEYCODE_BUTTON_L1: michael@0: case KeyEvent.KEYCODE_BUTTON_R1: michael@0: case KeyEvent.KEYCODE_BUTTON_L2: michael@0: case KeyEvent.KEYCODE_BUTTON_R2: michael@0: case KeyEvent.KEYCODE_BUTTON_THUMBL: michael@0: case KeyEvent.KEYCODE_BUTTON_THUMBR: michael@0: case KeyEvent.KEYCODE_BUTTON_START: michael@0: case KeyEvent.KEYCODE_BUTTON_SELECT: michael@0: case KeyEvent.KEYCODE_BUTTON_MODE: michael@0: case KeyEvent.KEYCODE_BUTTON_1: michael@0: case KeyEvent.KEYCODE_BUTTON_2: michael@0: case KeyEvent.KEYCODE_BUTTON_3: michael@0: case KeyEvent.KEYCODE_BUTTON_4: michael@0: case KeyEvent.KEYCODE_BUTTON_5: michael@0: case KeyEvent.KEYCODE_BUTTON_6: michael@0: case KeyEvent.KEYCODE_BUTTON_7: michael@0: case KeyEvent.KEYCODE_BUTTON_8: michael@0: case KeyEvent.KEYCODE_BUTTON_9: michael@0: case KeyEvent.KEYCODE_BUTTON_10: michael@0: case KeyEvent.KEYCODE_BUTTON_11: michael@0: case KeyEvent.KEYCODE_BUTTON_12: michael@0: case KeyEvent.KEYCODE_BUTTON_13: michael@0: case KeyEvent.KEYCODE_BUTTON_14: michael@0: case KeyEvent.KEYCODE_BUTTON_15: michael@0: case KeyEvent.KEYCODE_BUTTON_16: michael@0: return true; michael@0: default: michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: public static GeckoEvent createNativeGestureEvent(int action, PointF pt, double size) { michael@0: try { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.NATIVE_GESTURE_EVENT); michael@0: event.mAction = action; michael@0: event.mCount = 1; michael@0: event.mPoints = new Point[1]; michael@0: michael@0: PointF geckoPoint = new PointF(pt.x, pt.y); michael@0: geckoPoint = GeckoAppShell.getLayerView().convertViewPointToLayerPoint(geckoPoint); michael@0: michael@0: if (geckoPoint == null) { michael@0: // This could happen if Gecko isn't ready yet. michael@0: return null; michael@0: } michael@0: michael@0: event.mPoints[0] = new Point(Math.round(geckoPoint.x), Math.round(geckoPoint.y)); michael@0: michael@0: event.mX = size; michael@0: event.mTime = System.currentTimeMillis(); michael@0: return event; michael@0: } catch (Exception e) { michael@0: // This can happen if Gecko isn't ready yet michael@0: return null; michael@0: } michael@0: } michael@0: michael@0: /** michael@0: * Creates a GeckoEvent that contains the data from the MotionEvent. michael@0: * The keepInViewCoordinates parameter can be set to false to convert from the Java michael@0: * coordinate system (device pixels relative to the LayerView) to a coordinate system michael@0: * relative to gecko's coordinate system (CSS pixels relative to gecko scroll position). michael@0: */ michael@0: public static GeckoEvent createMotionEvent(MotionEvent m, boolean keepInViewCoordinates) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.MOTION_EVENT); michael@0: event.initMotionEvent(m, keepInViewCoordinates); michael@0: return event; michael@0: } michael@0: michael@0: private void initMotionEvent(MotionEvent m, boolean keepInViewCoordinates) { michael@0: mAction = m.getActionMasked(); michael@0: mTime = (System.currentTimeMillis() - SystemClock.elapsedRealtime()) + m.getEventTime(); michael@0: mMetaState = m.getMetaState(); michael@0: michael@0: switch (mAction) { michael@0: case MotionEvent.ACTION_CANCEL: michael@0: case MotionEvent.ACTION_UP: michael@0: case MotionEvent.ACTION_POINTER_UP: michael@0: case MotionEvent.ACTION_POINTER_DOWN: michael@0: case MotionEvent.ACTION_DOWN: michael@0: case MotionEvent.ACTION_MOVE: michael@0: case MotionEvent.ACTION_HOVER_ENTER: michael@0: case MotionEvent.ACTION_HOVER_MOVE: michael@0: case MotionEvent.ACTION_HOVER_EXIT: { michael@0: mCount = m.getPointerCount(); michael@0: mPoints = new Point[mCount]; michael@0: mPointIndicies = new int[mCount]; michael@0: mOrientations = new float[mCount]; michael@0: mPressures = new float[mCount]; michael@0: mPointRadii = new Point[mCount]; michael@0: mPointerIndex = m.getActionIndex(); michael@0: for (int i = 0; i < mCount; i++) { michael@0: addMotionPoint(i, i, m, keepInViewCoordinates); michael@0: } michael@0: break; michael@0: } michael@0: default: { michael@0: mCount = 0; michael@0: mPointerIndex = -1; michael@0: mPoints = new Point[mCount]; michael@0: mPointIndicies = new int[mCount]; michael@0: mOrientations = new float[mCount]; michael@0: mPressures = new float[mCount]; michael@0: mPointRadii = new Point[mCount]; michael@0: } michael@0: } michael@0: } michael@0: michael@0: private void addMotionPoint(int index, int eventIndex, MotionEvent event, boolean keepInViewCoordinates) { michael@0: try { michael@0: PointF geckoPoint = new PointF(event.getX(eventIndex), event.getY(eventIndex)); michael@0: if (!keepInViewCoordinates) { michael@0: geckoPoint = GeckoAppShell.getLayerView().convertViewPointToLayerPoint(geckoPoint); michael@0: } michael@0: michael@0: mPoints[index] = new Point(Math.round(geckoPoint.x), Math.round(geckoPoint.y)); michael@0: mPointIndicies[index] = event.getPointerId(eventIndex); michael@0: // getToolMajor, getToolMinor and getOrientation are API Level 9 features michael@0: if (Build.VERSION.SDK_INT >= 9) { michael@0: double radians = event.getOrientation(eventIndex); michael@0: mOrientations[index] = (float) Math.toDegrees(radians); michael@0: // w3c touchevents spec does not allow orientations == 90 michael@0: // this shifts it to -90, which will be shifted to zero below michael@0: if (mOrientations[index] == 90) michael@0: mOrientations[index] = -90; michael@0: michael@0: // w3c touchevent radius are given by an orientation between 0 and 90 michael@0: // the radius is found by removing the orientation and measuring the x and y michael@0: // radius of the resulting ellipse michael@0: // for android orientations >= 0 and < 90, the major axis should correspond to michael@0: // just reporting the y radius as the major one, and x as minor michael@0: // however, for a radius < 0, we have to shift the orientation by adding 90, and michael@0: // reverse which radius is major and minor michael@0: if (mOrientations[index] < 0) { michael@0: mOrientations[index] += 90; michael@0: mPointRadii[index] = new Point((int)event.getToolMajor(eventIndex)/2, michael@0: (int)event.getToolMinor(eventIndex)/2); michael@0: } else { michael@0: mPointRadii[index] = new Point((int)event.getToolMinor(eventIndex)/2, michael@0: (int)event.getToolMajor(eventIndex)/2); michael@0: } michael@0: } else { michael@0: float size = event.getSize(eventIndex); michael@0: Resources resources = GeckoAppShell.getContext().getResources(); michael@0: DisplayMetrics displaymetrics = resources.getDisplayMetrics(); michael@0: size = size*Math.min(displaymetrics.heightPixels, displaymetrics.widthPixels); michael@0: mPointRadii[index] = new Point((int)size,(int)size); michael@0: mOrientations[index] = 0; michael@0: } michael@0: if (!keepInViewCoordinates) { michael@0: // If we are converting to gecko CSS pixels, then we should adjust the michael@0: // radii as well michael@0: float zoom = GeckoAppShell.getLayerView().getViewportMetrics().zoomFactor; michael@0: mPointRadii[index].x /= zoom; michael@0: mPointRadii[index].y /= zoom; michael@0: } michael@0: mPressures[index] = event.getPressure(eventIndex); michael@0: } catch (Exception ex) { michael@0: Log.e(LOGTAG, "Error creating motion point " + index, ex); michael@0: mPointRadii[index] = new Point(0, 0); michael@0: mPoints[index] = new Point(0, 0); michael@0: } michael@0: } michael@0: michael@0: private static int HalSensorAccuracyFor(int androidAccuracy) { michael@0: switch (androidAccuracy) { michael@0: case SensorManager.SENSOR_STATUS_UNRELIABLE: michael@0: return GeckoHalDefines.SENSOR_ACCURACY_UNRELIABLE; michael@0: case SensorManager.SENSOR_STATUS_ACCURACY_LOW: michael@0: return GeckoHalDefines.SENSOR_ACCURACY_LOW; michael@0: case SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM: michael@0: return GeckoHalDefines.SENSOR_ACCURACY_MED; michael@0: case SensorManager.SENSOR_STATUS_ACCURACY_HIGH: michael@0: return GeckoHalDefines.SENSOR_ACCURACY_HIGH; michael@0: } michael@0: return GeckoHalDefines.SENSOR_ACCURACY_UNKNOWN; michael@0: } michael@0: michael@0: public static GeckoEvent createSensorEvent(SensorEvent s) { michael@0: int sensor_type = s.sensor.getType(); michael@0: GeckoEvent event = null; michael@0: michael@0: switch(sensor_type) { michael@0: michael@0: case Sensor.TYPE_ACCELEROMETER: michael@0: event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT); michael@0: event.mFlags = GeckoHalDefines.SENSOR_ACCELERATION; michael@0: event.mMetaState = HalSensorAccuracyFor(s.accuracy); michael@0: event.mX = s.values[0]; michael@0: event.mY = s.values[1]; michael@0: event.mZ = s.values[2]; michael@0: break; michael@0: michael@0: case 10 /* Requires API Level 9, so just use the raw value - Sensor.TYPE_LINEAR_ACCELEROMETER*/ : michael@0: event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT); michael@0: event.mFlags = GeckoHalDefines.SENSOR_LINEAR_ACCELERATION; michael@0: event.mMetaState = HalSensorAccuracyFor(s.accuracy); michael@0: event.mX = s.values[0]; michael@0: event.mY = s.values[1]; michael@0: event.mZ = s.values[2]; michael@0: break; michael@0: michael@0: case Sensor.TYPE_ORIENTATION: michael@0: event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT); michael@0: event.mFlags = GeckoHalDefines.SENSOR_ORIENTATION; michael@0: event.mMetaState = HalSensorAccuracyFor(s.accuracy); michael@0: event.mX = s.values[0]; michael@0: event.mY = s.values[1]; michael@0: event.mZ = s.values[2]; michael@0: break; michael@0: michael@0: case Sensor.TYPE_GYROSCOPE: michael@0: event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT); michael@0: event.mFlags = GeckoHalDefines.SENSOR_GYROSCOPE; michael@0: event.mMetaState = HalSensorAccuracyFor(s.accuracy); michael@0: event.mX = Math.toDegrees(s.values[0]); michael@0: event.mY = Math.toDegrees(s.values[1]); michael@0: event.mZ = Math.toDegrees(s.values[2]); michael@0: break; michael@0: michael@0: case Sensor.TYPE_PROXIMITY: michael@0: event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT); michael@0: event.mFlags = GeckoHalDefines.SENSOR_PROXIMITY; michael@0: event.mMetaState = HalSensorAccuracyFor(s.accuracy); michael@0: event.mX = s.values[0]; michael@0: event.mY = 0; michael@0: event.mZ = s.sensor.getMaximumRange(); michael@0: break; michael@0: michael@0: case Sensor.TYPE_LIGHT: michael@0: event = GeckoEvent.get(NativeGeckoEvent.SENSOR_EVENT); michael@0: event.mFlags = GeckoHalDefines.SENSOR_LIGHT; michael@0: event.mMetaState = HalSensorAccuracyFor(s.accuracy); michael@0: event.mX = s.values[0]; michael@0: break; michael@0: } michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createLocationEvent(Location l) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOCATION_EVENT); michael@0: event.mLocation = l; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createIMEEvent(ImeAction action) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT); michael@0: event.mAction = action.value; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createIMEKeyEvent(KeyEvent k) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_KEY_EVENT); michael@0: event.initKeyEvent(k, 0); michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createIMEReplaceEvent(int start, int end, michael@0: String text) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT); michael@0: event.mAction = ImeAction.IME_REPLACE_TEXT.value; michael@0: event.mStart = start; michael@0: event.mEnd = end; michael@0: event.mCharacters = text; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createIMESelectEvent(int start, int end) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT); michael@0: event.mAction = ImeAction.IME_SET_SELECTION.value; michael@0: event.mStart = start; michael@0: event.mEnd = end; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createIMECompositionEvent(int start, int end) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT); michael@0: event.mAction = ImeAction.IME_UPDATE_COMPOSITION.value; michael@0: event.mStart = start; michael@0: event.mEnd = end; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createIMERangeEvent(int start, michael@0: int end, int rangeType, michael@0: int rangeStyles, michael@0: int rangeLineStyle, michael@0: boolean rangeBoldLine, michael@0: int rangeForeColor, michael@0: int rangeBackColor, michael@0: int rangeLineColor) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.IME_EVENT); michael@0: event.mAction = ImeAction.IME_ADD_COMPOSITION_RANGE.value; michael@0: event.mStart = start; michael@0: event.mEnd = end; michael@0: event.mRangeType = rangeType; michael@0: event.mRangeStyles = rangeStyles; michael@0: event.mRangeLineStyle = rangeLineStyle; michael@0: event.mRangeBoldLine = rangeBoldLine; michael@0: event.mRangeForeColor = rangeForeColor; michael@0: event.mRangeBackColor = rangeBackColor; michael@0: event.mRangeLineColor = rangeLineColor; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createDrawEvent(Rect rect) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.DRAW); michael@0: event.mRect = rect; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createSizeChangedEvent(int w, int h, int screenw, int screenh) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.SIZE_CHANGED); michael@0: event.mPoints = new Point[2]; michael@0: event.mPoints[0] = new Point(w, h); michael@0: event.mPoints[1] = new Point(screenw, screenh); michael@0: return event; michael@0: } michael@0: michael@0: @RobocopTarget michael@0: public static GeckoEvent createBroadcastEvent(String subject, String data) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.BROADCAST); michael@0: event.mCharacters = subject; michael@0: event.mCharactersExtra = data; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createViewportEvent(ImmutableViewportMetrics metrics, DisplayPortMetrics displayPort) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.VIEWPORT); michael@0: event.mCharacters = "Viewport:Change"; michael@0: StringBuilder sb = new StringBuilder(256); michael@0: sb.append("{ \"x\" : ").append(metrics.viewportRectLeft) michael@0: .append(", \"y\" : ").append(metrics.viewportRectTop) michael@0: .append(", \"zoom\" : ").append(metrics.zoomFactor) michael@0: .append(", \"fixedMarginLeft\" : ").append(metrics.marginLeft) michael@0: .append(", \"fixedMarginTop\" : ").append(metrics.marginTop) michael@0: .append(", \"fixedMarginRight\" : ").append(metrics.marginRight) michael@0: .append(", \"fixedMarginBottom\" : ").append(metrics.marginBottom) michael@0: .append(", \"displayPort\" :").append(displayPort.toJSON()) michael@0: .append('}'); michael@0: event.mCharactersExtra = sb.toString(); michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createURILoadEvent(String uri) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOAD_URI); michael@0: event.mCharacters = uri; michael@0: event.mCharactersExtra = ""; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createWebappLoadEvent(String uri) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOAD_URI); michael@0: event.mCharacters = uri; michael@0: event.mCharactersExtra = "-webapp"; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createBookmarkLoadEvent(String uri) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOAD_URI); michael@0: event.mCharacters = uri; michael@0: event.mCharactersExtra = "-bookmark"; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createVisitedEvent(String data) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.VISITED); michael@0: event.mCharacters = data; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createNetworkEvent(int connectionType, boolean isWifi, int DHCPGateway) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.NETWORK_CHANGED); michael@0: event.mConnectionType = connectionType; michael@0: event.mIsWifi = isWifi; michael@0: event.mDHCPGateway = DHCPGateway; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createThumbnailEvent(int tabId, int bufw, int bufh, ByteBuffer buffer) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.THUMBNAIL); michael@0: event.mPoints = new Point[1]; michael@0: event.mPoints[0] = new Point(bufw, bufh); michael@0: event.mMetaState = tabId; michael@0: event.mBuffer = buffer; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createScreenOrientationEvent(short aScreenOrientation) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.SCREENORIENTATION_CHANGED); michael@0: event.mScreenOrientation = aScreenOrientation; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createCallObserverEvent(String observerKey, String topic, String data) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.CALL_OBSERVER); michael@0: event.mCharacters = observerKey; michael@0: event.mCharactersExtra = topic; michael@0: event.mData = data; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createRemoveObserverEvent(String observerKey) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.REMOVE_OBSERVER); michael@0: event.mCharacters = observerKey; michael@0: return event; michael@0: } michael@0: michael@0: @RobocopTarget michael@0: public static GeckoEvent createPreferencesObserveEvent(int requestId, String[] prefNames) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.PREFERENCES_OBSERVE); michael@0: event.mCount = requestId; michael@0: event.mPrefNames = prefNames; michael@0: return event; michael@0: } michael@0: michael@0: @RobocopTarget michael@0: public static GeckoEvent createPreferencesGetEvent(int requestId, String[] prefNames) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.PREFERENCES_GET); michael@0: event.mCount = requestId; michael@0: event.mPrefNames = prefNames; michael@0: return event; michael@0: } michael@0: michael@0: @RobocopTarget michael@0: public static GeckoEvent createPreferencesRemoveObserversEvent(int requestId) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.PREFERENCES_REMOVE_OBSERVERS); michael@0: event.mCount = requestId; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createLowMemoryEvent(int level) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.LOW_MEMORY); michael@0: event.mMetaState = level; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createNetworkLinkChangeEvent(String status) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.NETWORK_LINK_CHANGE); michael@0: event.mCharacters = status; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createTelemetryHistogramAddEvent(String histogram, michael@0: int value) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.TELEMETRY_HISTOGRAM_ADD); michael@0: event.mCharacters = histogram; michael@0: event.mCount = value; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createTelemetryUISessionStartEvent(String session, long timestamp) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.TELEMETRY_UI_SESSION_START); michael@0: event.mCharacters = session; michael@0: event.mTime = timestamp; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createTelemetryUISessionStopEvent(String session, String reason, long timestamp) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.TELEMETRY_UI_SESSION_STOP); michael@0: event.mCharacters = session; michael@0: event.mCharactersExtra = reason; michael@0: event.mTime = timestamp; michael@0: return event; michael@0: } michael@0: michael@0: public static GeckoEvent createTelemetryUIEvent(String action, String method, long timestamp, String extras) { michael@0: GeckoEvent event = GeckoEvent.get(NativeGeckoEvent.TELEMETRY_UI_EVENT); michael@0: event.mData = action; michael@0: event.mCharacters = method; michael@0: event.mCharactersExtra = extras; michael@0: event.mTime = timestamp; michael@0: return event; michael@0: } michael@0: michael@0: public void setAckNeeded(boolean ackNeeded) { michael@0: mAckNeeded = ackNeeded; michael@0: } michael@0: }