/* * AnBox, and an Android Blackbox application for the have-not-so-much-money's * Copyright (C) 2010 Yoonsoo Kim, Heekuk Lee, Heejin Sohn * * 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.ivehicle.AnBox; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.sql.Date; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Vector; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapController; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; import com.google.android.maps.Projection; import com.ivehicle.AnBox.SensorNotCaptured; import com.ivehicle.AnBox.SensorSample; import com.ivehicle.AnBox.R; import com.ivehicle.util.Log; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; // import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Point; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.Address; import android.location.Geocoder; import android.location.GpsSatellite; import android.location.Location; import android.location.LocationListener; import android.location.GpsStatus; import android.location.LocationManager; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; import android.widget.TextView; // import android.widget.Toast; //================================================== // carOrientation: ������°�. ȭ�� ǥ�����ؼ��� +PI/2 // ��Ÿ ��� ������ rad. // ��� �ӵ��� km/h //================================================== public class SensorTracker implements SensorEventListener, LocationListener, GpsStatus.Listener, DataStorageManager.DataRecorder { private SensorSampleIterator iter = null; private SensorSample lowerSample = null; private SensorSample middleSample = null; private SensorSample upperSample = null; private SensorSample returnSample = null; private long prevReqTime = 0; public interface OnShockEventListener { public void onShock(ShockEvent shockEvent); // in milli-seconds }; private Vector<OnShockEventListener> eventListeners = new Vector<OnShockEventListener>(); Handler handler = new Handler(); // address public String addressString = null; // longitude, latitude public Location currLoc = new Location(LocationManager.GPS_PROVIDER); // velocity, orientation public float velGPS = 0; private float carSpeed = 0; private float carOrientation = 0, theta_p = 0, theta_r = 0; // acc SensorManager sensorManager; private float curAcc[] = new float[3]; // acc w.r.t. local coordinates private float prevAcc[] = new float[3]; private float diffAccGlobal[] = new float[3]; public float[] accGlobal = new float[3];// = new float[3]; // acc w.r.t. global // coordinates public float[] prevAccGlobal = new float[3]; // acc w.r.t. global // coordinates public float[] velGlobal = new float[3]; // velocity (x,y,z) in global // coordinates. // Orientation private float orientation[] = new float[3]; // azimuth, pitch(-180~180), // roll(-90~90), private float mags[] = new float[3]; private boolean isReadyAcc = false; private boolean isReadyOri = false; // isReadyMags = false, // for calibration public int cnt=0; private long curT; // gps public int satellites = 0; private boolean towerEnabled = false, gpsEnabled = false; private boolean isUsingGps = false; LocationManager locationManager = null; LocationManager towerLocationManager = null; // calibration parameters public boolean isAccCalibrating = false, isAccCalibrated = false; public float[] accBound = new float[6]; // acc_x:min, max, // acc_y:min,max, // acc_z:min,max public float[] oriBound = new float[2]; private long lastUpdate = 0, timediff = 0; public float[] GravityCalibrated = { -SensorManager.STANDARD_GRAVITY, -SensorManager.STANDARD_GRAVITY, -SensorManager.STANDARD_GRAVITY }; // calibrated // gravity. // (default=-9.8) public float[] accStatic = new float[3]; // public float[] accCal = new float[3]; public float thetaPcal=0, thetaRcal = 0; public float thetaPStatic=0, thetaRStatic = 0; private float sp0,cr0,sr0; //cp0 private float sp=0,cp=1,sr=1,cr=0; // update period public int periodGpsUpdate; // GPS update period public int minimumDistance; // minimum distance for GPS update public int periodSensorRecording; // acc update period public long periodAccUpdate; public float accThreshold; // Config.WriteFileInterval. long WriteFileInterval = 5 * 60 * 1000; // 5�� private RecordActivity activity; RandomAccessFile sensorDataFile = null; // Shock public TimedDigitalFilter accHistory = new TimedDigitalFilter(Config.SHK_LENGTH); public double[] accMean = new double[3]; public boolean isShockOccurredX = false; public boolean isShockOccurredY = false; public boolean isShockOccurredZ = false; public boolean isShockReleased = true; RandomAccessFile accidentDataFile = null; private long latestShockTimeX=0,latestShockTimeY=0,latestShockTimeZ=0; private boolean recording = false; String shockTimeString = null; SimpleDateFormat shockTimeFormat = new SimpleDateFormat("HH:mm"); Date date = new Date(0); //MediaPlayer mpAccX, mpAccY, mpAccZ; public boolean mpPlayed = true; // private Toast toastS, toastE; final DecimalFormat df = new DecimalFormat("000"); final DecimalFormat dfLoc = new DecimalFormat(".000"); String currentStatus = null; public boolean isGpsEnabled = false; long wallClockTime; // map animation final int xBound = 100; final int yBound = 100; MapController mapController; public MyPositionOverlay positionOverlay; MapView myMapView; public SensorTracker(RecordActivity act) { // initialize activity = act; addressString = activity.getString(R.string.no_address); currentStatus = activity.getString(R.string.starting_sensor); shockTimeString = activity.getString(R.string.no_shock); } public void initMapView() { myMapView = (MapView) activity.findViewById(R.id.myMapView); mapController = myMapView.getController(); myMapView.setBuiltInZoomControls(true); // Configure the map display options myMapView.setSatellite(false); myMapView.setStreetView(true); //myMapView.setTraffic(true); // Zoom in mapController.setZoom(17); // Add the MyPositionOverlay positionOverlay = new MyPositionOverlay(); List<Overlay> overlays = myMapView.getOverlays(); try { if (positionOverlay != null || overlays != null) overlays.add(positionOverlay); } catch (Exception ex) { //activity.SetStatus("Overlay error: " + ex.getMessage()); } } public class TimedDigitalFilter { // final int history_len = 4; public double[] mLocHistoryX;// = new double[history_len]; public double[] mLocHistoryY; public double[] mLocHistoryZ; public long[] Time; int mLocPos = 0; int startPos = 0; int lastPos = 0; boolean isFilled = false; // ------------------------------------------------------------------------------------------------------------ public TimedDigitalFilter(int history_len) { mLocHistoryX = new double[history_len]; mLocHistoryY = new double[history_len]; mLocHistoryZ = new double[history_len]; Time = new long[history_len]; } long timeDiff() { return Time[lastPos] - Time[startPos]; } void clear() { mLocPos = startPos = lastPos=0; isFilled = false; for (int i=0;i<mLocHistoryX.length-1;i++) { mLocHistoryX[i]=mLocHistoryY[i]=mLocHistoryZ[i]=0; Time[i] = 0; } } void average(long t, float[] d, double[] res) { int div=0; res[0] = res[1] = res[2] = 0; mLocHistoryX[mLocPos] = d[0]; mLocHistoryY[mLocPos] = d[1]; mLocHistoryZ[mLocPos] = d[2]; Time[mLocPos] = t; lastPos = mLocPos; for (int i=0; i<mLocHistoryX.length; i++) { if (Time[i]-Time[startPos]<Config.MAX_SHK_TIME) { div++; res[0] += Math.abs(mLocHistoryX[i]); res[1] += Math.abs(mLocHistoryY[i]); res[2] += Math.abs(mLocHistoryZ[i]); } } // if (isFilled) // div = mLocHistoryX.length; // else // div= mLocPos; for (int i=0;i<3;i++) res[i] /=div; mLocPos++; if (mLocPos > mLocHistoryX.length - 1) { mLocPos = 0; isFilled = true; } if (isFilled) { startPos++; if (startPos > mLocHistoryX.length -1) startPos = 0; } } } private void fireShockEvent(long occurredAt) { if (eventListeners != null) { ShockEvent shockEvent = new ShockEvent(occurredAt); TextView myLocationText = (TextView) activity.findViewById(R.id.myLocationText); shockEvent.locString = myLocationText.getText().toString(); shockEvent.addr = activity.getAddressString(); shockEvent.sensorCapturedAt = accHistory.Time.clone(); shockEvent.mLocHistoryX = accHistory.mLocHistoryX.clone(); shockEvent.mLocHistoryY = accHistory.mLocHistoryY.clone(); shockEvent.mLocHistoryZ = accHistory.mLocHistoryZ.clone(); for (OnShockEventListener listener : eventListeners) { listener.onShock(shockEvent); } } //accHistory.clear(); } public void registerOnShockEventListener(OnShockEventListener listener) { eventListeners.add(listener); } public void unregisterOnShockEventListener( OnShockEventListener listener) { eventListeners.remove(listener); } public void initialize() { for (int i = 0; i < 3; i++) { curAcc[i] = prevAcc[i] = diffAccGlobal[i] = 0; accGlobal[i] = prevAccGlobal[i] = velGlobal[i] = 0; mags[i] = orientation[i] = 0; accStatic[i] = 0; accMean[i] = 0; } for (int i = 0; i < 6; i++) { accBound[i] = 0; } isAccCalibrating = false; isAccCalibrated = Config.isCalibrated(); oriBound[0] = oriBound[1] = 0; timediff = -1; lastUpdate = 0;// System.currentTimeMillis();//SystemClock.elapsedRealtime(); // isReadyMags = false; isReadyAcc = false; isReadyOri = false; periodGpsUpdate = Config.getGpsPeriod(); // GPS update period minimumDistance = Config.getGpsUpdateDistance(); // minimum distance for GPS update periodSensorRecording = Config.getSensorRecordingPeriod(); // sensor file write period periodAccUpdate = Config.getAccPeriod(); accThreshold = Config.getMinimumShockLevel(); } public synchronized String prepareRecording(long dateRestart) { Log.d(Config.TAG, toString() + ".prepareRecording()"); try { if (sensorDataFile != null) sensorDataFile.close(); File accFolder = new File(Config.getDataDir()); if (!accFolder.exists()) { Log.e(Config.TAG, "Could not write acc file "); activity.SetStatus("Could not write acc to file (no folder). "); } String sensorFileName = Config.getSensorFileName(dateRestart); File accFile = new File(sensorFileName); if (!accFile.exists()) { accFile.createNewFile(); } sensorDataFile = new RandomAccessFile(accFile, "rw"); return sensorFileName; } catch (IOException e) { Log.e(Config.TAG, "Could not write file " + e.getMessage()); activity.SetStatus("Could not write to file. " + e.getMessage()); } Log.d(Config.TAG, toString() + ".prepareRecording(): Returning"); return null; } // start & stop to support life-cycle of an activity public synchronized void start() { Log.d(Config.TAG, toString() + ".start()"); initialize(); if (!Config.isCalibrated()) { AccCalibration(); } else { isAccCalibrated = true; isAccCalibrating = false; GravityCalibrated = Config.getCalibratedGravities(); } StartSensorManager(); startHandler(); recording = true; Log.d(Config.TAG, toString() + ".start(): Returning"); } public synchronized void stop() { Log.d(Config.TAG, toString() + ".stop()"); recording = false; stopHandler(); StopSensorManager(); Log.d(Config.TAG, toString() + ".stop(): Returning"); } public synchronized boolean isRecording() { return recording; } // implements SensorEventListener public void onAccuracyChanged(Sensor arg0, int arg1) { // TODO Auto-generated method stub } public void AccCalibration() { // long startT = System.currentTimeMillis(); // Context context = activity.getApplicationContext(); // toastS = Toast.makeText(context, "Please, don't move, while calibrating sensors", // Toast.LENGTH_LONG); final AlertDialog dlg = new AlertDialog.Builder(activity) .setTitle(activity.getString(R.string.calibration_title)) .setMessage(activity.getString(R.string.calibration_start_msg)) .setPositiveButton(activity.getString(R.string.alert_dialog_ok), new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { } }).create(); dlg.show(); // toastE = Toast.makeText(context, "Calibration Ended", // Toast.LENGTH_SHORT); // toastS.show(); cnt=0;accCal[0]=accCal[1]=accCal[2]=thetaPcal=thetaRcal=0; isAccCalibrating = true; isAccCalibrated = false; final Handler hdlr = new Handler(); hdlr.postDelayed(new Runnable() { public void run() { isAccCalibrating = false; isAccCalibrated = true; for (int i=0; i<3;i++) { accStatic[i] = accCal[i]/cnt; accGlobal[i] = prevAccGlobal[i] = velGlobal[i]= 0; } thetaPStatic = thetaPcal/cnt; thetaRStatic = thetaRcal/cnt; sp0 = (float) Math.sin(thetaPStatic); // cp0 = (float) Math.cos(thetaPStatic * Math.PI / 180); sr0 = (float) Math.sin(thetaRStatic); cr0 = (float) Math.cos(thetaRStatic); GravityCalibrated[1] = accStatic[1]/sp0; GravityCalibrated[2] = -accStatic[2]/cr0; GravityCalibrated[0] = -accStatic[0]/sr0; SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(activity.getApplicationContext()); SharedPreferences.Editor prefEditor = pref.edit(); prefEditor.putFloat("calibrated_gravity_x", GravityCalibrated[0]); prefEditor.putFloat("calibrated_gravity_y", GravityCalibrated[1]); prefEditor.putFloat("calibrated_gravity_z", GravityCalibrated[2]); prefEditor.putBoolean("need_calibration", false); prefEditor.commit(); accHistory.clear(); isShockOccurredX = isShockOccurredY = isShockOccurredZ = false; dlg.setMessage(activity.getString(R.string.calibration_end_msg)); dlg.show(); hdlr.postDelayed(new Runnable() { public void run() { if (dlg.isShowing()) dlg.dismiss(); } }, 2000); // toastE.show(); // String text = "gx= "+String.valueOf(GravityCalibrated[0]) // +" \tgy= "+String.valueOf(GravityCalibrated[1]) // +" \tgz= "+String.valueOf(GravityCalibrated[2]); // activity.SetStatus(text); } }, Config.CAL_TIME); } public void onSensorChanged(SensorEvent event) { curT = event.timestamp; // in nanoseconds if (curT - lastUpdate < Config.getAccPeriod()) return; wallClockTime = System.currentTimeMillis(); // curT = System.currentTimeMillis(); //SystemClock.elapsedRealtime();// float dt; // timediff = SystemClock.elapsedRealtime() - lastUpdate; // lastUpdate = SystemClock.elapsedRealtime(); int type = event.sensor.getType(); // float accXmin,accXmax,accYmin,accYmax,accZmin,accZmax; // accXmin=accXmax=accYmin=accYmax=accZmin=accZmax=0; // float[] values = new float[3]; if (type == Sensor.TYPE_ACCELEROMETER) { isReadyAcc = true; timediff = curT - lastUpdate; if (timediff>0) { prevAcc = curAcc.clone(); curAcc = event.values.clone(); } if (lastUpdate == 0) { // initialize timediff = -1; } lastUpdate = curT; } else if (type == Sensor.TYPE_ORIENTATION) { isReadyOri = true; orientation = event.values.clone(); // orientation[0] = filter[3].average(orientation[0]); orientation[0] *= Config.DEG_TO_RAD; theta_p = orientation[1]*Config.DEG_TO_RAD;// = filter[4].average(orientation[1]); theta_r = orientation[2]*Config.DEG_TO_RAD;// = filter[5].average(orientation[2]); sp = (float) Math.sin(theta_p); cp = (float) Math.cos(theta_p); sr = (float) Math.sin(theta_r); cr = (float) Math.cos(theta_r); if (curAcc[2] < 0 && cr > 0) cr *= -1; } else { // isReadyMags = true; mags = event.values.clone(); } if (isAccCalibrating && isReadyAcc && isReadyOri) { isReadyAcc = isReadyOri = false; cnt++; for (int i = 0; i < 3; i++) { //accStatic[i] = filterAccGlobal[i].average(accGlobal[i]); accCal[i] += curAcc[i]; } thetaPcal += theta_p; thetaRcal += theta_r; } if (isAccCalibrated && isReadyAcc && timediff>0) {// isAccCalibrated && isReadyAcc && isReadyOri) { isReadyAcc =isReadyOri = false; // method 2 if (Math.abs(cp)<1e-3) accGlobal[0]=0; else accGlobal[0] = - (curAcc[1] - GravityCalibrated[1] * sp) / cp;//-curAcc[1]/cp - accStatic[0];// if (Math.abs(sr)<.1) { accGlobal[1] = 0; accGlobal[2] = 0; } else { //if (cr<0) cr = cr*-1; accGlobal[1] = -(curAcc[2]+GravityCalibrated[2]*cr)/sr;//-curAcc[2]/sr + accStatic[1];// accGlobal[2] = (curAcc[0]/sr + GravityCalibrated[0]);//curAcc[0]*sr - accStatic[2];// } dt = (float) timediff / 1000000000.0f; if (timediff <= 0) { velGlobal[0] = velGlobal[1] = velGlobal[2] = 0; diffAccGlobal[0] = diffAccGlobal[1] = diffAccGlobal[2] = 0; } else { for (int i = 0; i < 3; i++) { diffAccGlobal[i] = (accGlobal[i] - prevAccGlobal[i]) / (dt); velGlobal[i] += 3.6f * ((accGlobal[i] + prevAccGlobal[i]) * dt / 2); } } // Decide whether a shock has occurred //accHistory.average(wallClockTime, accGlobal, accMean); accHistory.average(curT, accGlobal, accMean); if ( !(isShockOccurredX || isShockOccurredY) ) { if (accMean[0] > accThreshold || accMean[1] > accThreshold) { if (accMean[0]>accMean[1]) { isShockOccurredX = true; latestShockTimeX = curT; } else{ isShockOccurredY = true; latestShockTimeY = curT; } fireShockEvent(wallClockTime); date.setTime(wallClockTime); shockTimeString = shockTimeFormat.format(date); mpPlayed = false; isShockReleased = false; } else if (accMean[2] > Config.getMinimumShockLevel()*.5) { isShockOccurredZ = true; latestShockTimeZ = curT; mpPlayed = false; isShockReleased = false; } } prevAccGlobal = accGlobal.clone(); //carSpeed = velGlobal[1]; carSpeed = velGPS; carOrientation = orientation[0]; // if (carSpeed <10) // currLoc.setBearing(orientation[0]); } /* * if (mags != null && curAcc != null && isReadyMags) { isReadyMags = * false; SensorManager.getRotationMatrix(mR, I, curAcc, mags); * SensorManager.remapCoordinateSystem(mR, SensorManager.AXIS_Z, * SensorManager.AXIS_MINUS_X, outR); SensorManager.getOrientation(outR, * oriFromMag); //int[] v = new int[3]; * * //oriFromMag = values.clone(); //oriFromMag[0] = * filter[0].average(values[0] * 100); //oriFromMag[1] = * filter[1].average(values[1] * 100); //oriFromMag[2] = * filter[2].average(values[2] * 100); * * //Exp.mText01.setText("" + v[0]); //Exp.mText02.setText("" + v[1]); * //Exp.mText03.setText("" + v[2]); } */ } public void StartSensorManager() { StartGpsManager(); sensorManager = (SensorManager) activity.getSystemService(Context.SENSOR_SERVICE); sensorManager.registerListener( this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_FASTEST); sensorManager.registerListener( this, sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_FASTEST); // sensorManager.registerListener( // this, // sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), // SensorManager.SENSOR_DELAY_FASTEST); currentStatus = activity.getString(R.string.sensing_started); } public void StopSensorManager() { StopGpsManager(); sensorManager.unregisterListener(this); currentStatus= activity.getString(R.string.sensing_stopped); if (sensorDataFile != null) { try { sensorDataFile.close(); } catch (IOException e) { Log.e(Config.TAG, e.toString()); } sensorDataFile = null; } } public void RestartSensorManagers() { stopHandler(); StopSensorManager(); StartSensorManager(); startHandler(); } public void StartGpsManager() { locationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE); towerLocationManager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE); CheckTowerAndGpsStatus(); if (gpsEnabled) { // gps satellite based locationManager.requestLocationUpdates( LocationManager.GPS_PROVIDER, periodGpsUpdate, minimumDistance, this); locationManager.addGpsStatusListener(this); isUsingGps = true; } else if (towerEnabled) { isUsingGps = false; // Cell tower and wifi based towerLocationManager.requestLocationUpdates( LocationManager.NETWORK_PROVIDER, periodGpsUpdate, minimumDistance, this); } else { isUsingGps = false; currentStatus = activity.getString(R.string.no_gps_provider); return; } // SetStatus("Started"); } private void CheckTowerAndGpsStatus() { towerEnabled = towerLocationManager.isProviderEnabled( LocationManager.NETWORK_PROVIDER); gpsEnabled = locationManager.isProviderEnabled( LocationManager.GPS_PROVIDER); } public void StopGpsManager() { towerLocationManager.removeUpdates(this); locationManager.removeUpdates(this); locationManager.removeGpsStatusListener(this); } public void startHandler() { //final TextView txtAccel = (TextView) activity.findViewById(R.id.txtAccel); final GraphView speedGraph = (GraphView) activity.findViewById(R.id.SpeedGraph); final GraphView accGraph = (GraphView) activity.findViewById(R.id.MapviewAccGraph); // final GraphView accGraphX = (GraphView) activity.findViewById(R.id.MapviewAccGraphX); // final GraphView accGraphZ = (GraphView) activity.findViewById(R.id.MapviewAccGraphZ); speedGraph.SetDataSize(50, 0, 20); accGraph.SetDataSize(50, 0, 20); // accGraphX.SetDataSize(50, 0, 20); // accGraphZ.SetDataSize(50, 0, 20); final TextView speedText = (TextView) activity.findViewById(R.id.SpeedText); final CompassView compassView = (CompassView)activity.findViewById(R.id.CompassView); final TextView Area = (TextView) activity.findViewById(R.id.Area); final TextView prevShockText = (TextView) activity.findViewById(R.id.ShockTime); handler.postDelayed(new Runnable() { public void run() { writeSensorToFile(); //tempDirection = tempDirection+5; compassView.RotateCompass((float)getCurrentOrientation()*Config.RAD_TO_DEG); speedText.setText( df.format(getCurrentSensorValue(SensorSample.VELOCITY)) + " km/h"); Area.setText(addressString); prevShockText.setText( activity.getString(R.string.shock_at) + " " + shockTimeString); //shock = accMean[0]+accMean[1]+accMean[2]; //shock = accMean[0];//Math.abs(getCurrentSensorValue(SensorSample.ACC_Y_VEHICLE)); accGraph.AppendData((float) accMean[1]); speedGraph.AppendData((float) accMean[1]); // accGraphX.AppendData((float) accMean[0]); // accGraphZ.AppendData((float) accMean[2]); if (isShockOccurredX) { if (curT - latestShockTimeX > Config.getShockRunningTime() * 1000000L) { isShockOccurredX = false; currentStatus = activity.getString(R.string.normal); isShockReleased = true; } else { currentStatus = activity.getString(R.string.side_shock); // if (!mpPlayed) { // mpAccX.start(); // mpPlayed = true; // } } } else if (isShockOccurredY) { if (curT - latestShockTimeY > Config.getShockRunningTime() * 1000000L) { isShockOccurredY = false; currentStatus = activity.getString(R.string.normal); isShockReleased = true; } else { currentStatus = activity.getString(R.string.frontal_shock); // if (!mpPlayed) { // mpAccY.start(); // mpPlayed = true; // } } } else if (isShockOccurredZ) { if (curT - latestShockTimeZ > Config.getShockRunningTime() * 1000000L) { isShockOccurredZ = false; currentStatus = activity.getString(R.string.normal); isShockReleased = true; } else { currentStatus= activity.getString(R.string.speed_bump); // if (!mpPlayed) { // mpAccZ.start(); // mpPlayed = true; // } } } activity.SetStatus(currentStatus); /* txtAccel.setText("X: " + df.format(getCurrentSensorValue(SensorSample.ACC_X_VEHICLE)) + "\tY: " + df.format(getCurrentSensorValue(SensorSample.ACC_Y_VEHICLE)) + "\tZ: " + df.format(getCurrentSensorValue(SensorSample.ACC_Z_VEHICLE)) + "\nori:" + df.format(getCurrentSensorValue(SensorSample.ORIENTATION)) + "\tpitch:" + String.valueOf(getCurrentSensorValue(SensorSample.THETA_P)) + "\troll:" + String.valueOf(getCurrentSensorValue(SensorSample.THETA_R)) + "\nvelGPS:\t" + df.format(velGPS) + "km/h" + "\nvelX:" + df.format(getCurrentSensorValue(SensorSample.VEL_X_VEHICLE)) + "km/h" + "\tvelY:" + df.format(getCurrentSensorValue(SensorSample.VEL_Y_VEHICLE)) + "km/h" + "\tvelZ:" + df.format(getCurrentSensorValue(SensorSample.VEL_Z_VEHICLE)) + "km/h" + "\nshock occured:" + String.valueOf(isShockOccurred) + "\nperiod: " + String.valueOf(accHistory.timeDiff()) + "\naccMean: "+ df.format(accMean[0]) +" \t"+ df.format(accMean[1]) +" \t"+ df.format(accMean[2])); */ handler.postDelayed(this, periodSensorRecording); } }, periodSensorRecording); } public void stopHandler() { handler.removeCallbacksAndMessages(null); } public void RestartGpsManagers() { StopGpsManager(); StartGpsManager(); } public void ResetManagersIfRequired() { CheckTowerAndGpsStatus(); // If GPS is enabled if (gpsEnabled) { // But we're not currently using GPS if (!isUsingGps) { RestartGpsManagers(); } // Else do nothing } } // implements LocationListener, GpsStatus.Listener public void onLocationChanged(Location location) { try { if (location != null) { updateWithNewLocation(location); Log.e(Config.TAG, "GeneralLocationListener.onLocationChanged(): location updated"); } } catch (Exception ex) { currentStatus = ex.getMessage(); Log.e(Config.TAG, ex.getMessage()); } } public void onProviderDisabled(String arg0) { updateWithNewLocation(null); } public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } public void onStatusChanged(String provider, int status, Bundle extras) { // TODO Auto-generated method stub } public void onGpsStatusChanged(int event) { switch (event) { case GpsStatus.GPS_EVENT_FIRST_FIX: currentStatus = activity.getString(R.string.gps_fix); isGpsEnabled = true; break; case GpsStatus.GPS_EVENT_SATELLITE_STATUS: GpsStatus status = locationManager.getGpsStatus(null); Iterator<GpsSatellite> it = status.getSatellites().iterator(); int count = 0; while (it.hasNext()) { count++; GpsSatellite oSat = (GpsSatellite) it.next(); Log.i(Config.TAG, "GeneralLocationListener.onGpsStatusChange(): Satellites:" + oSat.getSnr()); } satellites = count; // SetSatelliteInfo(count); break; case GpsStatus.GPS_EVENT_STARTED: currentStatus= activity.getString(R.string.gps_started); isGpsEnabled = false; break; case GpsStatus.GPS_EVENT_STOPPED: currentStatus = activity.getString(R.string.gps_stopped); isGpsEnabled = false; break; } } // For test: // int dcnt=0; private void updateWithNewLocation(Location location) { //Log.e(Config.TAG, "RecordActivity.updateWithNewLocation()"); TextView myLocationText = (TextView) activity.findViewById(R.id.myLocationText); String latLongString; // String addressString = "No address found"; if (isUsingGps) { // WriteToFile(location); // WriteToFileLoc(lastUpdate, location); // Update the map location. // For test: // location.setLatitude(location.getLatitude()+dcnt++*.0005); Double geoLat = location.getLatitude() * 1E6; Double geoLng = location.getLongitude() * 1E6; GeoPoint point = new GeoPoint(geoLat.intValue(), geoLng.intValue()); // map animation Point pxpoint = new Point(); Projection pxprojection = myMapView.getProjection(); pxprojection.toPixels(point, pxpoint); if ((pxpoint.x) < xBound || (pxpoint.x) > myMapView.getWidth() - xBound || (pxpoint.y) < yBound || (pxpoint.y) > myMapView.getHeight() - yBound) mapController.animateTo(point); // Update my location marker // activity.positionOverlay.setLocation(location); // Calculate speed by GPS // float t = location.distanceTo(positionOverlay.location) // / (location.getTime() - positionOverlay.location.getTime())*.0036f; // km/h // velGPS = velGlobal[1] = t; velGlobal[0] = velGlobal[2] = 0f; // z-axis. temporary. //location.setSpeed(t); // if (t<10) { // carOrientation = orientation[0]; // positionOverlay.isSetOrientation = true; // location.setBearing(carOrientation); // } // else // positionOverlay.isSetOrientation = false; location.setBearing(carOrientation); //location.setTime(wallClockTime); positionOverlay.setLocation(location); currLoc = location; velGPS = velGlobal[1] = location.getSpeed(); latLongString = activity.getString(R.string.latitude) + dfLoc.format(location.getLatitude()) + " " + activity.getString(R.string.longitude) + dfLoc.format(location.getLongitude()); } else { latLongString = activity.getString(R.string.no_location); } myLocationText.setText(latLongString); } public void writeSensorToFile() { try { String data = String.valueOf(System.currentTimeMillis()) + " " + String.valueOf(currLoc.getLatitude()) + " " + String.valueOf(currLoc.getLongitude()) + " " + String.valueOf(carSpeed) + " " + String.valueOf(carOrientation) + " " + String.valueOf(theta_p) + " " + String.valueOf(theta_r) + " " + String.valueOf(accGlobal[0]) + " " + String.valueOf(accGlobal[1]) + " " + String.valueOf(accGlobal[2]) + " " + String.valueOf(curAcc[0]) + " " + String.valueOf(curAcc[1]) + " " + String.valueOf(curAcc[2]) + " " + String.valueOf(mags[0]) + " " + String.valueOf(mags[1]) + " " + String.valueOf(mags[2]) + " " + String.valueOf(velGlobal[0]) + " " + String.valueOf(velGlobal[1]) + " " + String.valueOf(velGlobal[2]) + " " + String.valueOf(diffAccGlobal[0]) + " " + String.valueOf(diffAccGlobal[1]) + " " + String.valueOf(diffAccGlobal[2]) + " " + String.valueOf(velGPS) + "\n"; sensorDataFile.write(data.getBytes()); } catch (IOException e) { Log.e(Config.TAG, "Could not write file " + e.getMessage()); currentStatus = "Could not write to file. " + e.getMessage(); } } // provides clients with current values of various sensors public double getCurrentLongitude() { return currLoc.getLongitude(); } public double getCurrentLatitude() { return currLoc.getLatitude(); } public double getCurrentVelocity() { return (double) carSpeed; } public double getCurrentOrientation() { return (double) carOrientation; } public double getCurrentSensorValue(int sensorType) { switch (sensorType) { case SensorSample.LATITUDE: return currLoc.getLatitude(); case SensorSample.LONGITUDE: return currLoc.getLongitude(); case SensorSample.VELOCITY: return (double) carSpeed; case SensorSample.ORIENTATION: return (double) carOrientation; case SensorSample.THETA_P: return (double) theta_p; case SensorSample.THETA_R: return (double) theta_r; case SensorSample.ACC_X_VEHICLE: return (double) accGlobal[0]; case SensorSample.ACC_Y_VEHICLE: return (double) accGlobal[1]; case SensorSample.ACC_Z_VEHICLE: return (double) accGlobal[2]; case SensorSample.ACC_X_PHONE: return (double) curAcc[0]; case SensorSample.ACC_Y_PHONE: return (double) curAcc[1]; case SensorSample.ACC_Z_PHONE: return (double) curAcc[2]; case SensorSample.MAG_X: return mags[0]; case SensorSample.MAG_Y: return mags[1]; case SensorSample.MAG_Z: return mags[2]; case SensorSample.VEL_X_VEHICLE: return (double) velGlobal[0]; case SensorSample.VEL_Y_VEHICLE: return (double) velGlobal[1]; case SensorSample.VEL_Z_VEHICLE: return (double) velGlobal[2]; case SensorSample.DIFFACC_X_VEHICLE: return (double) diffAccGlobal[0]; case SensorSample.DIFFACC_Y_VEHICLE: return (double) diffAccGlobal[1]; case SensorSample.DIFFACC_Z_VEHICLE: return (double) diffAccGlobal[2]; default: return SensorSample.WRONG_SENSOR_TYPE; } } public double[] getCurrentAllSensorValues() { double[] ret = new double[SensorSample.ARRAY_SIZE]; for (int i = 0; i < SensorSample.ARRAY_SIZE; i++) ret[i] = getCurrentSensorValue(i); return ret; } // hjs public String getCurrentAddress() { double lat = currLoc.getLatitude(); double lng = currLoc.getLongitude(); Geocoder gc = new Geocoder(activity, Locale.getDefault()); StringBuilder sb = new StringBuilder(); try { List<Address> addresses = gc.getFromLocation(lat, lng, 1); if (addresses.size() > 0) { Address address = addresses.get(0); for (int i = 0; i < address.getMaxAddressLineIndex(); i++) sb.append(address.getAddressLine(i)).append("\n"); sb.append(address.getLocality()).append("\n"); sb.append(address.getPostalCode()).append("\n"); sb.append(address.getCountryName()); } addressString = sb.toString(); } catch (IOException e) { currentStatus = e.getMessage(); } return addressString; } // provides clients with sensor values at a specified time public void prepareSensorValueHistorySince(long timeInMs) throws SensorNotCaptured { iter = new SensorSampleIterator(timeInMs); lowerSample = iter.next(); middleSample = iter.next(); upperSample = iter.next(); } public void doneWithSensorValueHistory() { iter = null; lowerSample = null; middleSample = null; upperSample = null; } public double getLongitudeAt(long timeInMs) throws SensorNotCaptured { return getAllSensorValuesAt(timeInMs)[SensorSample.LONGITUDE]; } public double getLatitudeAt(long timeInMs) throws SensorNotCaptured { return getAllSensorValuesAt(timeInMs)[SensorSample.LATITUDE]; } public double getVelocityAt(long timeInMs) throws SensorNotCaptured { return getAllSensorValuesAt(timeInMs)[SensorSample.VELOCITY]; } public double getOrientationAt(long timeInMs) throws SensorNotCaptured { return getAllSensorValuesAt(timeInMs)[SensorSample.ORIENTATION]; } public double getSensorValueAt(long timeInMs, int sensorType) throws SensorNotCaptured { return getAllSensorValuesAt(timeInMs)[sensorType]; } public double[] getAllSensorValuesAt(long timeInMs) throws SensorNotCaptured { return getSensorSampleAt(timeInMs).values; } public SensorSample getSensorSampleAt(long timeInMs) throws SensorNotCaptured { // little optimization for getXXXAt(), removing lb & ub computation and // condition check if (prevReqTime == timeInMs) { return returnSample; } else { prevReqTime = timeInMs; } long lb = (lowerSample.sampledAt + middleSample.sampledAt) / 2; long ub = (middleSample.sampledAt + upperSample.sampledAt) / 2; if (lb <= timeInMs && timeInMs < ub) { // time is between lb and ub returnSample = middleSample; return returnSample; } else if (ub <= timeInMs) { // time is greater than or equal to ub while (iter.hasNext()) { lowerSample = middleSample; middleSample = upperSample; upperSample = iter.next(); lb = (lowerSample.sampledAt + middleSample.sampledAt) / 2; ub = (middleSample.sampledAt + upperSample.sampledAt) / 2; if (lb <= timeInMs && timeInMs < ub) { returnSample = middleSample; return returnSample; } } // boundary condition check if (upperSample.sampledAt + 10 * 1000 <= timeInMs) { throw new SensorNotCaptured(timeInMs); } else { returnSample = upperSample; return returnSample; } } else { // time is less than lb. bound condition check if (timeInMs < lowerSample.sampledAt - 10 * 1000) { throw new SensorNotCaptured(timeInMs); } else { returnSample = lowerSample; return returnSample; } } } }