Adding support for defining external (or internal in Android's case) sensors. This is still a work in progress. Major task yet to complete is defining the coordinate system to return the sensor data. 3 sensor types are defined: Magnetic, Accelerometer, Orientation. Right now the sensor data is returned in device coordinates for Magnetic and Acceleration, and World (Earth) coordinates for Orientation. Sensors use the Input Manager to define triggers and listeners like all other input types. Only Android has an implementation for SensorInput at this time. See forum post http://jmonkeyengine.org/groups/android/forum/topic/creating-engine-support-for-android-sensor-input/ for details of the operation and current status.
git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9610 75d07b2b-3a1a-0410-a2c5-0572b91ccdca3.0
parent
1fbc0cc406
commit
bb631ab13a
@ -0,0 +1,584 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.input.android; |
||||
|
||||
import android.content.Context; |
||||
import android.hardware.Sensor; |
||||
import android.hardware.SensorEvent; |
||||
import android.hardware.SensorEventListener; |
||||
import android.hardware.SensorManager; |
||||
import android.view.Display; |
||||
import android.view.Surface; |
||||
import android.view.WindowManager; |
||||
import com.jme3.input.RawInputListener; |
||||
import com.jme3.input.SensorInput; |
||||
import com.jme3.input.event.MotionSensorEvent; |
||||
import com.jme3.math.Vector3f; |
||||
import com.jme3.system.android.JmeAndroidSystem; |
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.util.Map.Entry; |
||||
import java.util.Set; |
||||
import java.util.logging.Level; |
||||
import java.util.logging.Logger; |
||||
|
||||
/** |
||||
* Android specific implementation of SensorInput. |
||||
* |
||||
* @author iwgeric |
||||
*/ |
||||
public class AndroidSensorInput implements SensorInput, SensorEventListener { |
||||
private final static Logger logger = Logger.getLogger(AndroidSensorInput.class.getName()); |
||||
|
||||
private SensorManager sensorManager = null; |
||||
private RawInputListener listener = null; |
||||
private Map<Integer, SensorData> sensors = new HashMap<Integer, SensorData>(); |
||||
private boolean initialized = false; |
||||
private WindowManager window; |
||||
private Display disp; |
||||
|
||||
private final float[] curAccValues = new float[3]; |
||||
private final float[] curMagValues = new float[3]; |
||||
private final float[] curInclination = new float[9]; |
||||
private final float[] curRotation = new float[9]; |
||||
private final float[] rotatedRotation = new float[9]; |
||||
|
||||
private final ArrayList<MotionSensorEvent> eventQueue = new ArrayList<MotionSensorEvent>(); |
||||
|
||||
/** |
||||
* Internal class to enclose data for each sensor. |
||||
*/ |
||||
private class SensorData { |
||||
int androidSensorType = -1; |
||||
int androidSensorSpeed = SensorManager.SENSOR_DELAY_UI; |
||||
Sensor sensor = null; |
||||
Vector3f lastValues = new Vector3f(); |
||||
float minChangePercent = 0f; |
||||
boolean enabled = false; |
||||
boolean paused = false; |
||||
|
||||
public SensorData(int androidSensorType, Sensor sensor) { |
||||
this.androidSensorType = androidSensorType; |
||||
this.sensor = sensor; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Pauses the active sensors to save battery. Mostly used internally so that |
||||
* the sensors can be deactivated while the game Activity is |
||||
* in the background to save battery life |
||||
*/ |
||||
public void pauseSensors() { |
||||
for (Entry<Integer, SensorData> entry : sensors.entrySet()) { |
||||
SensorData sensorData = entry.getValue(); |
||||
if (sensorData.sensor != null) { |
||||
unRegisterListener(entry.getKey()); |
||||
sensorData.paused = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Resumes paused sensors. Mostly used internally so that |
||||
* the sensors can be reactivated when the game Activity is |
||||
* placed back onto the forefront. |
||||
*/ |
||||
public void resumeSensors() { |
||||
for (Entry<Integer, SensorData> entry : sensors.entrySet()) { |
||||
SensorData sensorData = entry.getValue(); |
||||
if (sensorData.sensor != null && sensorData.paused) { |
||||
if (registerListener(entry.getKey())) { |
||||
sensorData.paused = false; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Used internally by the context to reset the Sensor Manager on device rotations. |
||||
* Necessary because a new Activity is created on a device rotation, so the |
||||
* Sensor Manager needs to be reset with the new Activity. |
||||
*/ |
||||
public void resetSensorManager() { |
||||
initSensorManager(); |
||||
} |
||||
|
||||
private void initSensorManager() { |
||||
window = JmeAndroidSystem.getActivity().getWindowManager(); |
||||
disp = window.getDefaultDisplay(); |
||||
|
||||
sensorManager = (SensorManager) JmeAndroidSystem.getActivity().getSystemService(Context.SENSOR_SERVICE); |
||||
|
||||
initSensor(SensorInput.SENSOR_TYPE_MAGNETIC_FIELD); |
||||
initSensor(SensorInput.SENSOR_TYPE_ACCELEROMETER); |
||||
initSensor(SensorInput.SENSOR_TYPE_ORIENTATION); |
||||
|
||||
} |
||||
|
||||
private boolean initSensor(int sensorType) { |
||||
boolean result = false; |
||||
boolean previouslyActive = false; |
||||
|
||||
SensorData sensorData = sensors.get((Integer)sensorType); |
||||
if (sensorData != null) { |
||||
if (sensorData.enabled) { |
||||
previouslyActive = true; |
||||
} |
||||
unRegisterListener(sensorType); |
||||
} else { |
||||
sensorData = new SensorData(sensorType, null); |
||||
sensors.put(sensorType, sensorData); |
||||
} |
||||
|
||||
switch (sensorType) { |
||||
case SensorInput.SENSOR_TYPE_MAGNETIC_FIELD: |
||||
sensorData.androidSensorType = Sensor.TYPE_MAGNETIC_FIELD; |
||||
sensorData.sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); |
||||
break; |
||||
case SensorInput.SENSOR_TYPE_ACCELEROMETER: |
||||
sensorData.androidSensorType = Sensor.TYPE_ACCELEROMETER; |
||||
sensorData.sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); |
||||
break; |
||||
case SensorInput.SENSOR_TYPE_ORIENTATION: |
||||
sensorData.androidSensorType = Sensor.TYPE_ORIENTATION; |
||||
//Orientation is not a sensor anymore but rather a call to SensorMangaer
|
||||
// to get the current orientation based on the Magnetic and Accelerometer sensor data
|
||||
sensorData.sensor = null; |
||||
break; |
||||
|
||||
default: |
||||
throw new IllegalArgumentException("Invalid Sensor Type."); |
||||
} |
||||
|
||||
if (sensorData.sensor != null || sensorType == SensorInput.SENSOR_TYPE_ORIENTATION) { |
||||
logger.log(Level.INFO, "Sensor Type {0} found.", sensorType); |
||||
if (previouslyActive) { |
||||
logger.log(Level.INFO, "Reactivating Sensor Type {0}.", sensorType); |
||||
registerListener(sensorType); |
||||
} |
||||
result = true; |
||||
} |
||||
|
||||
|
||||
return result; |
||||
} |
||||
|
||||
private boolean registerListener(int sensorType) { |
||||
SensorData sensorData = sensors.get((Integer)sensorType); |
||||
if (sensorData != null) { |
||||
if (sensorData.enabled) { |
||||
logger.log(Level.INFO, "Sensor Already Active: SensorType: {0}, active: {1}", |
||||
new Object[]{sensorType, sensorData.enabled}); |
||||
return true; |
||||
} |
||||
if (sensorData.sensor != null) { |
||||
if (sensorManager.registerListener(this, sensorData.sensor, sensorData.androidSensorSpeed)) { |
||||
sensorData.enabled = true; |
||||
logger.log(Level.INFO, "SensorType: {0}, active: {1}", |
||||
new Object[]{sensorType, sensorData.enabled}); |
||||
logger.log(Level.INFO, "Sensor Type {0} activated.", sensorType); |
||||
return true; |
||||
} else { |
||||
sensorData.enabled = false; |
||||
logger.log(Level.INFO, "Sensor Type {0} activation failed.", sensorType); |
||||
} |
||||
} else if (sensorType == SensorInput.SENSOR_TYPE_ORIENTATION) { |
||||
logger.log(Level.INFO, "Sensor is Orientation"); |
||||
if (registerListener(SensorInput.SENSOR_TYPE_MAGNETIC_FIELD) && registerListener(SensorInput.SENSOR_TYPE_ACCELEROMETER)) { |
||||
sensorData.enabled = true; |
||||
logger.log(Level.INFO, "Magnetic and Acceleration Sensors Registered and Orientation Sensor being simulated."); |
||||
return true; |
||||
} |
||||
} |
||||
sensorData.lastValues = null; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private void unRegisterListener(int sensorType) { |
||||
SensorData sensorData = sensors.get((Integer)sensorType); |
||||
if (sensorData != null) { |
||||
if (sensorData.sensor != null) { |
||||
sensorManager.unregisterListener(this, sensorData.sensor); |
||||
} else if (sensorType == SensorInput.SENSOR_TYPE_ORIENTATION) { |
||||
logger.log(Level.INFO, "Mangetic and Acceleration Sensors are being deactivated with Orientation Sensor."); |
||||
unRegisterListener(SensorInput.SENSOR_TYPE_MAGNETIC_FIELD); |
||||
unRegisterListener(SensorInput.SENSOR_TYPE_ACCELEROMETER); |
||||
} |
||||
sensorData.enabled = false; |
||||
logger.log(Level.INFO, "SensorType: {0}, active: {1}", |
||||
new Object[]{sensorType, sensorData.enabled}); |
||||
logger.log(Level.INFO, "Sensor Type {0} deactivated.", sensorType); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
* Android remapCoordinateSystem from the Android docs |
||||
* remapCoordinateSystem(float[] inR, int X, int Y, float[] outR) |
||||
* |
||||
* @param inR the rotation matrix to be transformed. Usually it is the matrix |
||||
* returned by getRotationMatrix(float[], float[], float[], float[]). |
||||
* |
||||
* @param outR the transformed rotation matrix. inR and outR can be the same |
||||
* array, but it is not recommended for performance reason. |
||||
* |
||||
* X defines on which world axis and direction the X axis of the device is mapped. |
||||
* Y defines on which world axis and direction the Y axis of the device is mapped. |
||||
* |
||||
* @return True if successful |
||||
*/ |
||||
|
||||
private boolean remapCoordinates(float[] inR, float[] outR) { |
||||
int xDir = SensorManager.AXIS_X; |
||||
int yDir = SensorManager.AXIS_Y; |
||||
|
||||
// logger.log(Level.INFO, "Screen Rotation: {0}", getScreenRotation());
|
||||
if (getScreenRotation() == Surface.ROTATION_0) { |
||||
xDir = SensorManager.AXIS_X; |
||||
yDir = SensorManager.AXIS_Y; |
||||
} |
||||
if (getScreenRotation() == Surface.ROTATION_90) { |
||||
xDir = SensorManager.AXIS_MINUS_Y; |
||||
yDir = SensorManager.AXIS_MINUS_X; |
||||
} |
||||
if (getScreenRotation() == Surface.ROTATION_180) { |
||||
xDir = SensorManager.AXIS_MINUS_X; |
||||
yDir = SensorManager.AXIS_MINUS_Y; |
||||
} |
||||
if (getScreenRotation() == Surface.ROTATION_270) { |
||||
xDir = SensorManager.AXIS_Y; |
||||
yDir = SensorManager.AXIS_MINUS_X; |
||||
} |
||||
return SensorManager.remapCoordinateSystem(inR, xDir, yDir, outR); |
||||
} |
||||
|
||||
/** |
||||
* Returns the current device rotation. |
||||
* Surface.ROTATION_0 = device in natural default rotation |
||||
* Surface.ROTATION_90 = device in rotated 90deg counterclockwise |
||||
* Surface.ROTATION_180 = device in rotated 180deg counterclockwise |
||||
* Surface.ROTATION_270 = device in rotated 270deg counterclockwise |
||||
* |
||||
* When the Manifest locks the orientation, this value will not change during |
||||
* gametime, but if the orientation of the screen is based off the sensor, |
||||
* this value will change as the device is rotated. |
||||
* @return Current device rotation amount |
||||
*/ |
||||
private int getScreenRotation() { |
||||
|
||||
return disp.getRotation(); |
||||
} |
||||
|
||||
private Integer getAndroidSensorSpeed(int sensorInputSpeed) { |
||||
Integer androidSpeed = null; |
||||
switch (sensorInputSpeed) { |
||||
case SensorInput.SENSOR_SPEED_SLOW: |
||||
androidSpeed = SensorManager.SENSOR_DELAY_UI; |
||||
break; |
||||
case SensorInput.SENSOR_SPEED_MEDIUM: |
||||
androidSpeed = SensorManager.SENSOR_DELAY_NORMAL; |
||||
break; |
||||
case SensorInput.SENSOR_SPEED_FAST: |
||||
androidSpeed = SensorManager.SENSOR_DELAY_GAME; |
||||
break; |
||||
default: |
||||
throw new IllegalArgumentException("Invalid Sensor Speed."); |
||||
} |
||||
return androidSpeed; |
||||
} |
||||
|
||||
/** |
||||
* Calculates the device orientation based off the data recieved from the |
||||
* Acceleration Sensor and Mangetic Field sensor |
||||
* Values are returned relative to the Earth. |
||||
* |
||||
* From the Android Doc |
||||
* |
||||
* Computes the device's orientation based on the rotation matrix. When it returns, the array values is filled with the result: |
||||
* values[0]: azimuth, rotation around the Z axis. |
||||
* values[1]: pitch, rotation around the X axis. |
||||
* values[2]: roll, rotation around the Y axis. |
||||
* |
||||
* The reference coordinate-system used is different from the world |
||||
* coordinate-system defined for the rotation matrix: |
||||
* X is defined as the vector product Y.Z (It is tangential to the ground at the device's current location and roughly points West). |
||||
* Y is tangential to the ground at the device's current location and points towards the magnetic North Pole. |
||||
* Z points towards the center of the Earth and is perpendicular to the ground. |
||||
* |
||||
* @return |
||||
*/ |
||||
private boolean updateOrientation() { |
||||
SensorData sensorData; |
||||
sensorData = sensors.get((Integer)SensorInput.SENSOR_TYPE_MAGNETIC_FIELD); |
||||
if (sensorData == null || !sensorData.enabled) { |
||||
return false; |
||||
} |
||||
sensorData = sensors.get((Integer)SensorInput.SENSOR_TYPE_ACCELEROMETER); |
||||
if (sensorData == null || !sensorData.enabled) { |
||||
return false; |
||||
} |
||||
|
||||
sensorData = sensors.get((Integer)SensorInput.SENSOR_TYPE_ORIENTATION); |
||||
if (sensorData != null && sensorData.enabled) { |
||||
|
||||
// create new copies so they don't get updated during the getRotationMatrix call
|
||||
final float[] accValues = new float[3]; |
||||
final float[] magValues = new float[3]; |
||||
synchronized(curAccValues) { |
||||
accValues[0] = curAccValues[0]; |
||||
accValues[1] = curAccValues[1]; |
||||
accValues[2] = curAccValues[2]; |
||||
} |
||||
synchronized(curMagValues) { |
||||
magValues[0] = curMagValues[0]; |
||||
magValues[1] = curMagValues[1]; |
||||
magValues[2] = curMagValues[2]; |
||||
} |
||||
|
||||
if (SensorManager.getRotationMatrix(curRotation, curInclination, accValues, magValues)) { |
||||
final float [] orientValues = new float[3]; |
||||
if (remapCoordinates(curRotation, rotatedRotation)) { |
||||
SensorManager.getOrientation(rotatedRotation, orientValues); |
||||
// logger.log(Level.INFO, "Orientation Values: {0}, {1}, {2}",
|
||||
// new Object[]{orientValues[0], orientValues[1], orientValues[2]});
|
||||
|
||||
updateEventQueue(SensorInput.SENSOR_TYPE_ORIENTATION, |
||||
orientValues[0], orientValues[1], orientValues[2], System.nanoTime()); |
||||
|
||||
return true; |
||||
} else { |
||||
//logger.log(Level.INFO, "remapCoordinateSystem failed");
|
||||
} |
||||
|
||||
} else { |
||||
//logger.log(Level.INFO, "getRotationMatrix returned false");
|
||||
} |
||||
|
||||
} else { |
||||
if (!sensorData.enabled) { |
||||
//logger.log(Level.INFO, "Orientation is not active");
|
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private void updateEventQueue(int sensorType, float x, float y, float z, long timestamp) { |
||||
// logger.log(Level.INFO, "updateEventQueue for {0}: values: {1}, {2}, {3}",
|
||||
// new Object[]{sensorType, x, y, z});
|
||||
float lastX, lastY, lastZ; |
||||
float dX, dY, dZ; |
||||
|
||||
SensorData sensorData = sensors.get((Integer)sensorType); |
||||
|
||||
if (sensorData != null) { |
||||
// if lastValues is null, then this is the first scan after a registerListener
|
||||
// so set lastValues to the current values so dX,dY,dZ are zero this pass
|
||||
if (sensorData.lastValues == null) { |
||||
sensorData.lastValues = new Vector3f(x, y, z); |
||||
} |
||||
|
||||
lastX = sensorData.lastValues.x; |
||||
lastY = sensorData.lastValues.y; |
||||
lastZ = sensorData.lastValues.z; |
||||
|
||||
dX = x - lastX; |
||||
dY = y - lastY; |
||||
dZ = z - lastZ; |
||||
|
||||
if (dX != 0 && dY != 0 && dZ != 0) { |
||||
MotionSensorEvent motionEvent = new MotionSensorEvent(sensorType, x, y, z, dX, dY, dZ); |
||||
motionEvent.setTime(timestamp); |
||||
sensorData.lastValues.x = x; |
||||
sensorData.lastValues.y = y; |
||||
sensorData.lastValues.z = z; |
||||
|
||||
synchronized (eventQueue){ |
||||
eventQueue.add(motionEvent); |
||||
} |
||||
} else { |
||||
//logger.log(Level.INFO, "No change in Sensor Data for: {0}", sensorType);
|
||||
} |
||||
} else { |
||||
//logger.log(Level.INFO, "Sensor Data is null for: {0}", sensorType);
|
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Start of methods from SensorInput
|
||||
|
||||
public boolean isEnabled(int sensorType) { |
||||
logger.log(Level.INFO, "Checking isEnabled for type: {0}", sensorType); |
||||
SensorData sensorData = sensors.get((Integer)sensorType); |
||||
if (sensorData == null) { |
||||
// logger.log(Level.INFO, "sensor data is null, sensors size is: {0}", sensors.size());
|
||||
return false; |
||||
} |
||||
return sensors.get((Integer)sensorType).enabled; |
||||
} |
||||
|
||||
public void setEnable(boolean enable) { |
||||
for (Integer sensorType: sensors.keySet()) { |
||||
setEnable(sensorType, enable); |
||||
} |
||||
} |
||||
|
||||
public void setEnable(int sensorType, boolean enable) { |
||||
logger.log(Level.INFO, "Setting Sensor {0} Enable to {1}", |
||||
new Object[]{sensorType, enable}); |
||||
if (enable) { |
||||
// registerListener(sensorType, true);
|
||||
registerListener(sensorType); |
||||
} else { |
||||
unRegisterListener(sensorType); |
||||
} |
||||
} |
||||
|
||||
public void setSensorFrequency(int sensorType, int updateSpeed) { |
||||
SensorData sensorData = sensors.get((Integer)sensorType); |
||||
if (sensorData == null || sensorData.enabled) { |
||||
throw new IllegalArgumentException("Sensor Type Not Configured or is already active."); |
||||
} |
||||
|
||||
sensorData.androidSensorSpeed = getAndroidSensorSpeed(updateSpeed); |
||||
} |
||||
|
||||
public Set<Integer> getSensorTypes() { |
||||
return Collections.unmodifiableSet(sensors.keySet()); |
||||
} |
||||
|
||||
public void setSensorMinChange(int sensorType, float minChangePercent) { |
||||
throw new UnsupportedOperationException("Not supported yet."); |
||||
} |
||||
|
||||
public void initialize() { |
||||
logger.log(Level.INFO, "Doing Initialize."); |
||||
initSensorManager(); |
||||
initialized = true; |
||||
} |
||||
|
||||
public void update() { |
||||
updateOrientation(); |
||||
synchronized (eventQueue){ |
||||
// flush events to listener
|
||||
for (int i = 0; i < eventQueue.size(); i++){ |
||||
listener.onMotionSensorEvent(eventQueue.get(i)); |
||||
} |
||||
eventQueue.clear(); |
||||
} |
||||
} |
||||
|
||||
public void destroy() { |
||||
for (Integer i: sensors.keySet()) { |
||||
unRegisterListener(i); |
||||
} |
||||
logger.log(Level.INFO, "Doing Destroy"); |
||||
if (sensorManager != null) { |
||||
sensorManager.unregisterListener(this); |
||||
} |
||||
sensors.clear(); |
||||
eventQueue.clear(); |
||||
} |
||||
|
||||
public boolean isInitialized() { |
||||
return initialized; |
||||
} |
||||
|
||||
public void setInputListener(RawInputListener listener) { |
||||
this.listener = listener; |
||||
} |
||||
|
||||
public long getInputTimeNanos() { |
||||
return System.nanoTime(); |
||||
} |
||||
|
||||
// End of methods from SensorInput
|
||||
|
||||
// Start of methods from SensorEventListener
|
||||
|
||||
public void onSensorChanged(SensorEvent se) { |
||||
// logger.log(Level.INFO, "onSensorChanged for {0}: values: {1}, {2}, {3}",
|
||||
// new Object[]{se.sensor.getType(), se.values[0], se.values[1], se.values[2]});
|
||||
SensorData sensorData; |
||||
int sensorType; |
||||
for (Entry<Integer, SensorData> entry : sensors.entrySet()) { |
||||
// if (entry.getValue().sensor == null) {
|
||||
// logger.log(Level.INFO, "Sensor is null for SensorType: {0}", entry.getKey());
|
||||
// }
|
||||
if (entry.getValue().sensor != null && entry.getValue().sensor.equals(se.sensor)) { |
||||
sensorType = entry.getKey(); |
||||
sensorData = entry.getValue(); |
||||
|
||||
updateEventQueue(sensorType, se.values[0], se.values[1], se.values[2], se.timestamp); |
||||
|
||||
if (sensorType == SensorInput.SENSOR_TYPE_MAGNETIC_FIELD) { |
||||
synchronized(curMagValues) { |
||||
curMagValues[0] = se.values[0]; |
||||
curMagValues[1] = se.values[1]; |
||||
curMagValues[2] = se.values[2]; |
||||
} |
||||
} |
||||
if (sensorType == SensorInput.SENSOR_TYPE_ACCELEROMETER) { |
||||
synchronized(curAccValues) { |
||||
curAccValues[0] = se.values[0]; |
||||
curAccValues[1] = se.values[1]; |
||||
curAccValues[2] = se.values[2]; |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
|
||||
public void onAccuracyChanged(Sensor sensor, int i) { |
||||
logger.log(Level.INFO, "onAccuracyChanged for {0}: accuracy: {1}", |
||||
new Object[]{sensor.toString(), i}); |
||||
} |
||||
|
||||
// End of methods from SensorEventListener
|
||||
|
||||
} |
@ -0,0 +1,146 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.input; |
||||
|
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* A specific API for interfacing with sensors. |
||||
* |
||||
* In order to conserve battery power for handheld devices, sensors must be |
||||
* enabled before data will be sent. Use the setEnable method to enable or disable |
||||
* the sensors. |
||||
* |
||||
* Sensor speed can also be set. Constants in this class are used so that each |
||||
* platform implementation can decide what absolute update rate to use. Use the |
||||
* setSensorFrequency method to set the desired update rate. |
||||
* |
||||
* In order to minimize the amount of data sent to the application, there is a |
||||
* method available to set how much change is required between sensor readings |
||||
* before the new updated data is sent. Use the setSensorMinChange method to set |
||||
* a minimum data change percentage (percentage of max sensor range). Data will |
||||
* not be sent to the application until the data has changed by this amount. |
||||
* |
||||
* |
||||
* |
||||
* |
||||
* |
||||
* @author iwgeric |
||||
*/ |
||||
public interface SensorInput extends Input { |
||||
|
||||
/** |
||||
* Orientation Sensor. Values returned in the onMotionSensorChanged event |
||||
* are in radians. |
||||
*/ |
||||
public static final int SENSOR_TYPE_ORIENTATION = 0; |
||||
|
||||
/** |
||||
* Accelerometer Sensor. Values returned in the onMotionSensorChanged event |
||||
* are in m/s^2. Values include gravity. To get true device acceleration, |
||||
* gravity must be removed. |
||||
*/ |
||||
public static final int SENSOR_TYPE_ACCELEROMETER = 1; |
||||
|
||||
/** |
||||
* Magnetic Field Sensor. Values returned in the onMotionSensorChanged event |
||||
* are in micro-Tesla (uT). |
||||
*/ |
||||
public static final int SENSOR_TYPE_MAGNETIC_FIELD = 2; |
||||
|
||||
/** |
||||
* Slowest Sensor Update Speed |
||||
*/ |
||||
public static final int SENSOR_SPEED_SLOW = 0; |
||||
|
||||
/** |
||||
* Medium Sensor Update Speed |
||||
*/ |
||||
public static final int SENSOR_SPEED_MEDIUM = 1; |
||||
|
||||
/** |
||||
* Fastest Sensor Update Speed |
||||
*/ |
||||
public static final int SENSOR_SPEED_FAST = 2; |
||||
|
||||
/** |
||||
* Returns whether a sensor is enabled or not. |
||||
* |
||||
* @param sensorType The sensor type. |
||||
* @return whether a sensor is enabled or not. |
||||
*/ |
||||
public boolean isEnabled(int sensorType); |
||||
|
||||
/** |
||||
* Sets enable/disable for a specific sensor type. |
||||
* |
||||
* @param sensorType The sensor type. |
||||
* @param enable True to enable, False to disable. |
||||
*/ |
||||
public void setEnable(int sensorType, boolean enable); |
||||
|
||||
/** |
||||
* Sets enable/disable for all sensor types. |
||||
* |
||||
* @param enable True to enable, False to disable. |
||||
*/ |
||||
public void setEnable(boolean enable); |
||||
|
||||
/** |
||||
* Returns a list of available sensor types. |
||||
* |
||||
* @return a list of available sensor types. |
||||
*/ |
||||
public Set<Integer> getSensorTypes(); |
||||
|
||||
/** |
||||
* Set the minimum amount of change that is required before an event |
||||
* is created for the sensor. minChangePercent is defined as a percentage |
||||
* of the maximum sensor range. |
||||
* |
||||
* @param sensorType The sensor type. |
||||
* @param minChangePercent Percentage of changed required before creating an event. |
||||
*/ |
||||
public void setSensorMinChange(int sensorType, float minChangePercent); |
||||
|
||||
/** |
||||
* Set the update frequency for the sensor. Use the defined constants in |
||||
* SensorInput for setting the speed becuase the actual update frequency is |
||||
* platform dependant. |
||||
* |
||||
* @param sensorType The sensor type. |
||||
* @param updateSpeed Target update speed as a constant (do not use absolute values) |
||||
*/ |
||||
public void setSensorFrequency(int sensorType, int updateSpeed); |
||||
|
||||
} |
@ -0,0 +1,58 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.input.controls; |
||||
|
||||
import com.jme3.input.SensorInput; |
||||
|
||||
/** |
||||
* <code>MotionSensorListener</code> is used to receive events from Sensors |
||||
* |
||||
* @author iwgeric |
||||
*/ |
||||
public interface MotionSensorListener extends InputListener { |
||||
|
||||
/** |
||||
* Called when data from a sensor has been updated. |
||||
* |
||||
* @param name The name of the mapping that was invoked |
||||
* @param sensorType Sensor Type value from {@link SensorInput}. |
||||
* @param x X component of the new sensor data based on the sensor type. |
||||
* @param y Y component of the new sensor data based on the sensor type. |
||||
* @param z Z component of the new sensor data based on the sensor type. |
||||
* @param dX Change in the x component from the last update. |
||||
* @param dY Change in the y component from the last update. |
||||
* @param dZ Change in the z component from the last update. |
||||
*/ |
||||
public void onMotionSensorChange(String name, int sensorType, float x, float y, float z, float dX, float dY, float dZ); |
||||
|
||||
} |
@ -0,0 +1,83 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.input.controls; |
||||
|
||||
import com.jme3.input.SensorInput; |
||||
|
||||
/** |
||||
* A <code>SensorTrigger</code> is used as a mapping to receive events |
||||
* from a sensor. |
||||
* |
||||
* @author Kirill Vainer |
||||
*/ |
||||
public class SensorTrigger implements Trigger { |
||||
|
||||
// private final SensorInput.Type sensorType;
|
||||
private final int sensorType; |
||||
|
||||
/** |
||||
* Create a new <code>SensorTrigger</code> to receive sensor events. |
||||
* |
||||
* @param Sensor Type. See {@link SensorInput}. |
||||
*/ |
||||
// public SensorTrigger(SensorInput.Type sensorType) {
|
||||
public SensorTrigger(int sensorType) { |
||||
// if (sensorType == null)
|
||||
if (sensorType < 0 || sensorType > 255) |
||||
throw new IllegalArgumentException("Invalide Sensor Type"); |
||||
|
||||
this.sensorType = sensorType; |
||||
} |
||||
|
||||
// public SensorInput.Type getSensorType() {
|
||||
public int getSensorType() { |
||||
return sensorType; |
||||
} |
||||
|
||||
public String getName() { |
||||
return sensorType + " Sensor"; |
||||
} |
||||
|
||||
// public static int sensorHash(SensorInput.Type sensorType){
|
||||
public static int sensorHash(int sensorType){ |
||||
// assert sensorType != null;
|
||||
// return 256 | (sensorType.ordinal() & 0xff);
|
||||
assert sensorType >= 0 && sensorType <= 255; |
||||
return 1024 | (sensorType & 0xff); |
||||
} |
||||
|
||||
public int triggerHashCode() { |
||||
return sensorHash(sensorType); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,118 @@ |
||||
/* |
||||
* Copyright (c) 2009-2010 jMonkeyEngine |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors |
||||
* may be used to endorse or promote products derived from this software |
||||
* without specific prior written permission. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
|
||||
package com.jme3.input.event; |
||||
|
||||
/** |
||||
* Motion Sensor event. |
||||
* |
||||
* @author iwgeric |
||||
*/ |
||||
public class MotionSensorEvent extends InputEvent { |
||||
|
||||
private int sensorType; |
||||
private float x, y, z, dX, dY, dZ; |
||||
|
||||
public MotionSensorEvent(int sensorType, float x, float y, float z, float dX, float dY, float dZ) { |
||||
this.sensorType = sensorType; |
||||
this.x = x; |
||||
this.y = y; |
||||
this.z = z; |
||||
this.dX = dX; |
||||
this.dY = dY; |
||||
this.dZ = dZ; |
||||
} |
||||
|
||||
/** |
||||
* Sensor Type |
||||
* @return Sensor Type |
||||
*/ |
||||
public int getSensorType() { |
||||
return sensorType; |
||||
} |
||||
|
||||
/** |
||||
* Current X coordinate |
||||
* @return Current X coordinate |
||||
*/ |
||||
public float getX() { |
||||
return x; |
||||
} |
||||
|
||||
/** |
||||
* Current Y coordinate |
||||
* @return Current Y coordinate |
||||
*/ |
||||
public float getY() { |
||||
return y; |
||||
} |
||||
|
||||
/** |
||||
* Current Z coordinate |
||||
* @return Current Z coordinate |
||||
*/ |
||||
public float getZ() { |
||||
return z; |
||||
} |
||||
|
||||
/** |
||||
* The change in X coordinate |
||||
* @return change in X coordinate |
||||
*/ |
||||
public float getDX() { |
||||
return dX; |
||||
} |
||||
|
||||
/** |
||||
* The change in Y coordinate |
||||
* |
||||
* @return change in Y coordinate |
||||
*/ |
||||
public float getDY() { |
||||
return dY; |
||||
} |
||||
|
||||
/** |
||||
* The change in Z coordinate |
||||
* |
||||
* @return change in Z coordinate |
||||
*/ |
||||
public float getDZ() { |
||||
return dZ; |
||||
} |
||||
|
||||
@Override |
||||
public String toString(){ |
||||
return "MotionSensor(Type="+sensorType+", X="+x+", Y="+y+", Z="+z+", DX="+dX+", DY="+dY+", DZ="+dZ+")"; |
||||
} |
||||
|
||||
} |
Loading…
Reference in new issue