package loon.android;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import loon.Accelerometer;
import loon.AccelerometerState;
import loon.LSystem;
import loon.action.map.Config;
import loon.event.SysKey;
import loon.utils.MathUtils;
import loon.utils.processes.RealtimeProcess;
import loon.utils.processes.RealtimeProcessManager;
import loon.utils.timer.LTimerContext;
public class AndroidAccelerometer implements Accelerometer {
// 四方向手机朝向
private SensorDirection _direction = SensorDirection.EMPTY;
// 八方向手机朝向
private int _all_direction = Config.EMPTY;
private Event event;
private long lastUpdate;
private float currentX, currentY, currentZ, currenForce;
private float lastX, lastY, lastZ;
private float orientation, magnitude;
private final AccelerometerState _state = new AccelerometerState();
private int _sleep = 30;
private SensorManager manager;
private final float[] accelerometerValues = new float[3];
private final float[] magneticFieldValues = new float[3];
private SensorEventListener accelerometerListener;
private SensorProcess sensorProcess;
private Loon _game;
public AndroidAccelerometer(Loon game) {
super();
this._game = game;
}
private final void onOrientation(float x, float y, float z) {
// 换算手机翻转角度
orientation = 0;
magnitude = x * x + y * y;
if (magnitude * 4 >= z * z) {
float angle = MathUtils.atan2(-y, x) * MathUtils.RAD_TO_DEG;
orientation = 90 - MathUtils.round(angle);
while (orientation >= 360) {
orientation -= 360;
}
while (orientation < 0) {
orientation += 360;
}
}
// 将手机翻转角度转为手机朝向
if (LSystem.checkAngle(0, orientation)
|| LSystem.checkAngle(360, orientation)) {
_all_direction = Config.TUP;
_direction = SensorDirection.UP;
} else if (LSystem.checkAngle(45, orientation)) {
_all_direction = Config.LEFT;
_direction = SensorDirection.LEFT;
} else if (LSystem.checkAngle(90, orientation)) {
_all_direction = Config.TLEFT;
_direction = SensorDirection.LEFT;
} else if (LSystem.checkAngle(135, orientation)) {
_all_direction = Config.DOWN;
_direction = SensorDirection.LEFT;
} else if (LSystem.checkAngle(180, orientation)) {
_all_direction = Config.TDOWN;
_direction = SensorDirection.DOWN;
} else if (LSystem.checkAngle(225, orientation)) {
_all_direction = Config.RIGHT;
_direction = SensorDirection.RIGHT;
} else if (LSystem.checkAngle(270, orientation)) {
_all_direction = Config.TRIGHT;
_direction = SensorDirection.RIGHT;
} else if (LSystem.checkAngle(315, orientation)) {
_all_direction = Config.UP;
_direction = SensorDirection.RIGHT;
} else {
_all_direction = Config.EMPTY;
_direction = SensorDirection.EMPTY;
}
}
private final void onSensor(float[] values) {
synchronized (this) {
long curTime = System.currentTimeMillis();
if (LSystem.base() != null && LSystem.base().setting.landscape()) {
currentX = -values[0];
currentY = -values[1];
currentZ = -values[2];
} else {
currentX = values[0];
currentY = values[1];
currentZ = values[2];
}
onOrientation(currentX, currentY, currentZ);
if ((curTime - lastUpdate) > 30) {
long diffTime = (curTime - lastUpdate);
lastUpdate = curTime;
currenForce = MathUtils.abs(currentX + currentY + currentZ
- lastX - lastY - lastZ)
/ diffTime * 10000;
if (currenForce > 500 && event != null) {
event.onShakeChanged(currenForce);
}
}
lastX = currentX;
lastY = currentY;
lastZ = currentZ;
if (event != null) {
event.onDirection(_direction, currentX, currentY, currentZ);
}
}
}
private class SensorListener implements SensorEventListener {
final float[] accelerometerValues;
final float[] magneticFieldValues;
SensorListener(float[] accelerometerValues, float[] magneticFieldValues) {
this.accelerometerValues = accelerometerValues;
this.magneticFieldValues = magneticFieldValues;
}
@Override
public void onAccuracyChanged(Sensor a, int b) {
}
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
if (!(LSystem.base() != null && LSystem.base().setting
.landscape())) {
System.arraycopy(event.values, 0, accelerometerValues, 0,
accelerometerValues.length);
} else {
accelerometerValues[0] = event.values[1];
accelerometerValues[1] = -event.values[0];
accelerometerValues[2] = event.values[2];
}
}
if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
System.arraycopy(event.values, 0, magneticFieldValues, 0,
magneticFieldValues.length);
}
onSensor(accelerometerValues);
_state.getAcceleration().set(currentX, currentY, currentZ);
try {
Thread.sleep(_sleep);
} catch (InterruptedException e) {
}
}
}
class SensorProcess extends RealtimeProcess {
final float[] accelerometerValues;
public SensorProcess(float[] values) {
this.accelerometerValues = values;
this.setDelay(_sleep);
}
public void run(LTimerContext context) {
if (_state.isConnected()) {
accelerometerValues[2] = -1f;
if (SysKey.isDown() && SysKey.getKeyCode() == SysKey.LEFT) {
accelerometerValues[0]--;
}
if (SysKey.isDown() && SysKey.getKeyCode() == SysKey.RIGHT) {
accelerometerValues[0]++;
}
if (SysKey.isDown() && SysKey.getKeyCode() == SysKey.UP) {
accelerometerValues[1]++;
}
if (SysKey.isDown() && SysKey.getKeyCode() == SysKey.DOWN) {
accelerometerValues[1]--;
}
onSensor(accelerometerValues);
_state.getAcceleration().set(currentX, currentY, currentZ);
}
}
}
@Override
public void start() {
// 模拟器下启动时键盘模拟重力
if (AndroidGame.isEmulator()) {
_state.setConnected(true);
sensorProcess = new SensorProcess(accelerometerValues);
RealtimeProcessManager.get().addProcess(sensorProcess);
return;
}
if (!_state.isConnected() && manager == null) {
manager = (SensorManager) _game
.getSystemService(Context.SENSOR_SERVICE);
if (manager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() == 0) {
_state.setConnected(false);
} else {
Sensor accelerometer = manager.getSensorList(
Sensor.TYPE_ACCELEROMETER).get(0);
accelerometerListener = new SensorListener(
this.accelerometerValues, this.magneticFieldValues);
_state.setConnected(manager.registerListener(
accelerometerListener, accelerometer,
SensorManager.SENSOR_DELAY_GAME));
}
// 如果无法正常启动,则开启伪重力感应
if (!_state.isConnected()) {
_state.setConnected(true);
sensorProcess = new SensorProcess(accelerometerValues);
RealtimeProcessManager.get().addProcess(sensorProcess);
}
}
}
public void stop() {
if (manager != null) {
if (accelerometerListener != null) {
manager.unregisterListener(accelerometerListener);
accelerometerListener = null;
}
manager = null;
_state.setConnected(false);
} else {
_state.setConnected(false);
}
}
@Override
public float getLastX() {
return lastX;
}
@Override
public float getLastY() {
return lastY;
}
@Override
public float getLastZ() {
return lastZ;
}
@Override
public float getX() {
return currentX;
}
@Override
public float getY() {
return currentY;
}
@Override
public float getZ() {
return currentZ;
}
@Override
public final AccelerometerState getState() {
return _state;
}
@Override
public int getSleep() {
return _sleep;
}
@Override
public void sleep(int sleep) {
this._sleep = sleep;
if (sensorProcess != null) {
sensorProcess.setDelay(sleep);
}
}
/**
* 屏幕方向(返回Config类中配置值)
*
* @return
*/
@Override
public int getAllDirection() {
return _all_direction;
}
@Override
public Event getEvent() {
return event;
}
/**
* 事件监听
*
* @param event
*/
@Override
public void setEvent(Event event) {
this.event = event;
}
/**
* 屏幕旋转度数
*
* @return
*/
@Override
public float getOrientation() {
return orientation;
}
/**
* 返回四方向手机朝向
*
* @return
*/
@Override
public SensorDirection getDirection() {
return _direction;
}
}