/* MultiWii EZ-GUI Copyright (C) <2012> Bartosz Szczygiel (eziosoft) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.ezio.multiwii.helpers; import java.lang.reflect.Method; import java.util.Iterator; import android.content.Context; import android.hardware.GeomagneticField; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.Criteria; import android.location.GpsSatellite; import android.location.GpsStatus; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.os.Bundle; import android.provider.Settings; import android.util.Log; import android.widget.Toast; import com.google.android.gms.maps.model.LatLng; public class Sensors implements SensorEventListener, LocationListener { private Listener mListener = null; Location location, oldLocation; LowPassFilter filterYaw = new LowPassFilter(0.03f); LowPassFilter filterPitch = new LowPassFilter(0.03f); LowPassFilter filterRoll = new LowPassFilter(0.03f); private LocationManager locationManager; private String provider; GeomagneticField geoField; public int PhoneNumSat = 0; public double PhoneLatitude = 0; public double PhoneLongitude = 0; public double PhoneAltitude = 0; public double PhoneSpeed = 0; public int PhoneFix = 0; public float PhoneAccuracy = 0; public float Declination = 0; public LatLng MapCurrentPosition = new LatLng(0, 0); SensorManager m_sensorManager; float[] m_lastMagFields = new float[3];; float[] m_lastAccels = new float[3];; private float[] m_rotationMatrix = new float[16]; private float[] m_orientation = new float[4]; public float Pitch = 0.f; public float Heading = 0.f; public float Roll = 0.f; private Context context; String mocLocationProvider; public boolean MockLocationWorking = false; public interface Listener { public void onSensorsStateChangeMagAcc(); public void onSensorsStateGPSLocationChange(); public void onSensorsStateGPSStatusChange(); } public void registerListener(Listener listener) { mListener = listener; } public void initMOCKLocation() { mocLocationProvider = LocationManager.GPS_PROVIDER; locationManager.addTestProvider(mocLocationProvider, false, false, false, false, true, true, true, 0, 5); locationManager.setTestProviderEnabled(mocLocationProvider, true); MockLocationWorking = true; } public boolean isMockEnabled() { try { int mock_location = Settings.Secure.getInt(context.getContentResolver(), "mock_location"); if (mock_location == 0) { try { Settings.Secure.putInt(context.getContentResolver(), "mock_location", 1); } catch (Exception ex) { } mock_location = Settings.Secure.getInt(context.getContentResolver(), "mock_location"); } if (mock_location == 0) { Toast.makeText(context, "Turn on the mock locations in your Android settings", Toast.LENGTH_LONG).show(); return false; } else { return true; } } catch (Exception ex) { ex.printStackTrace(); } return false; } public void setMOCKLocation(double Latitude, double Longitude, float Altitude, float Heading, float speed) { Location mockLocation = new Location(mocLocationProvider); // a string mockLocation.setLatitude(Latitude); // double mockLocation.setLongitude(Longitude); mockLocation.setAltitude(Altitude); mockLocation.setTime(System.currentTimeMillis()); mockLocation.setAccuracy(1); mockLocation.setBearing(Heading); mockLocation.setSpeed(speed * 0.01f); try { Method locationJellyBeanFixMethod = Location.class.getMethod("makeComplete"); if (locationJellyBeanFixMethod != null) { locationJellyBeanFixMethod.invoke(mockLocation); } } catch (Exception e) { // TODO: handle exception } locationManager.setTestProviderLocation(mocLocationProvider, mockLocation); } public void ClearMOCKLocation() { if (mocLocationProvider != null) { Log.d("aaa", "ClearMOCKLocation"); locationManager.clearTestProviderEnabled(mocLocationProvider); locationManager.clearTestProviderLocation(mocLocationProvider); locationManager.clearTestProviderStatus(mocLocationProvider); locationManager.removeTestProvider(mocLocationProvider); start(); MockLocationWorking = false; } } public Sensors(Context context) { this.context = context; m_sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); Criteria criteria = new Criteria(); // if (!app.D) criteria.setAccuracy(Criteria.ACCURACY_FINE); provider = locationManager.getBestProvider(criteria, false); location = locationManager.getLastKnownLocation(provider); if (location != null) { geoField = new GeomagneticField(Double.valueOf(location.getLatitude()).floatValue(), Double.valueOf(location.getLongitude()).floatValue(), Double.valueOf(location.getAltitude()).floatValue(), System.currentTimeMillis()); Declination = geoField.getDeclination(); MapCurrentPosition = new LatLng(location.getLatitude(), location.getLongitude()); oldLocation = location; } locationManager.addGpsStatusListener(new GpsStatus.Listener() { @Override public void onGpsStatusChanged(int event) { if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) { GpsStatus status = locationManager.getGpsStatus(null); Iterable<GpsSatellite> sats = status.getSatellites(); Iterator<GpsSatellite> it = sats.iterator(); PhoneNumSat = 0; while (it.hasNext()) { GpsSatellite oSat = (GpsSatellite) it.next(); if (oSat.usedInFix()) PhoneNumSat++; } } if (event == GpsStatus.GPS_EVENT_FIRST_FIX) PhoneFix = 1; if (mListener != null) mListener.onSensorsStateGPSStatusChange(); } }); } public void start() { registerListeners(); } public void startMagACC() { m_sensorManager.registerListener(this, m_sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_GAME); m_sensorManager.registerListener(this, m_sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL); } public void stopMagACC() { m_sensorManager.unregisterListener(this); } private void registerListeners() { locationManager.requestLocationUpdates(provider, 0, 0, this); } private void unregisterListeners() { stopMagACC(); locationManager.removeUpdates(this); } public void stop() { unregisterListeners(); } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onSensorChanged(SensorEvent event) { switch (event.sensor.getType()) { case Sensor.TYPE_ACCELEROMETER: System.arraycopy(event.values, 0, m_lastAccels, 0, 3); break; case Sensor.TYPE_MAGNETIC_FIELD: System.arraycopy(event.values, 0, m_lastMagFields, 0, 3); break; default: return; } computeOrientation(); } private void computeOrientation() { if (SensorManager.getRotationMatrix(m_rotationMatrix, null, m_lastAccels, m_lastMagFields)) { SensorManager.getOrientation(m_rotationMatrix, m_orientation); float yaw = (float) (Math.toDegrees(m_orientation[0]) + Declination); float pitch = (float) Math.toDegrees(m_orientation[1]); float roll = (float) Math.toDegrees(m_orientation[2]); Heading = filterYaw.lowPass(yaw); Pitch = filterPitch.lowPass(pitch); Roll = filterRoll.lowPass(roll); if (mListener != null) mListener.onSensorsStateChangeMagAcc(); } } @Override public void onLocationChanged(Location location) { oldLocation = this.location; this.location = location; PhoneLatitude = location.getLatitude(); PhoneLongitude = location.getLongitude(); PhoneAltitude = location.getAltitude(); PhoneSpeed = location.getSpeed() * 100f; PhoneAccuracy = location.getAccuracy() * 100f; MapCurrentPosition = new LatLng(location.getLatitude(), location.getLongitude()); geoField = new GeomagneticField(Double.valueOf(location.getLatitude()).floatValue(), Double.valueOf(location.getLongitude()).floatValue(), Double.valueOf(location.getAltitude()).floatValue(), System.currentTimeMillis()); Declination = geoField.getDeclination(); if (mListener != null) mListener.onSensorsStateGPSLocationChange(); } @Override public void onProviderDisabled(String provider) { } @Override public void onProviderEnabled(String provider) { } @Override public void onStatusChanged(String provider, int status, Bundle extras) { } public LatLng getNextPredictedLocationOnlineMap() { if (location != null && oldLocation != null) { int lat = (int) ((location.getLatitude() + (location.getLatitude() - oldLocation.getLatitude()))); int lon = (int) ((location.getLongitude() + (location.getLongitude() - oldLocation.getLongitude()))); return new LatLng(lat, lon); } else return new LatLng(0, 0); } }