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 +}