Panagiotis Triantafyllou

telematics addition

......@@ -65,10 +65,11 @@
android:screenOrientation="portrait"
android:theme="@style/SDKAppTheme" />
<!-- android:screenOrientation="portrait"-->
<activity
android:name="ly.warp.sdk.activities.TelematicsActivity"
android:exported="false"
android:screenOrientation="portrait"
android:configChanges="orientation|screenSize"
android:theme="@style/SDKAppTheme" />
<activity
......
......@@ -4,6 +4,7 @@ import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
......@@ -14,7 +15,7 @@ import android.location.LocationManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
......@@ -27,6 +28,7 @@ import androidx.core.content.ContextCompat;
import com.google.android.material.snackbar.Snackbar;
import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
......@@ -39,7 +41,6 @@ import java.util.Arrays;
import io.github.inflationx.viewpump.ViewPumpContextWrapper;
import ly.warp.sdk.R;
import ly.warp.sdk.db.WarplyDBHelper;
/**
* Created by Panagiotis Triantafyllou on 26/June/2023.
......@@ -58,30 +59,33 @@ public class TelematicsActivity extends Activity implements View.OnClickListener
private ImageView mIvBack;
private boolean mIsTripStarted = false;
private LinearLayout mLlTripButton, mLlTelematicsMain;
private TextView mTvTripButton, mTvSensorData, mTvVelocity, mTvAvgVelocity, mTvRecordsSaved;
private TextView mTvTripButton, mTvSensorData, mTvVelocity, mTvAvgVelocity, mTvRecordsSaved,
mTvOrientationCount, mTvTouchCount;
private SensorManager mSensorManager;
private Sensor mSensor;
private Handler mHandler, mLoctionHandler;
private Runnable mRunnable, mLocationRunnable;
private Handler mHandler, mLocationHandler, mTouchHandler;
private Runnable mRunnable, mLocationRunnable, mTouchRunnable;
private long lastUpdate = 0;
private float lastX, lastY, lastZ;
private float velocity = 0;
private ArrayList<JSONObject> mAccelerationTimestamps = new ArrayList<>();
float mAcceleration = 0;
private float mAcceleration = 0;
private static final float ALPHA = 0.8f; // Filter factor
private static final float STOP_THRESHOLD = 8.0f; // Stop threshold in m/s²
private static final int PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 4000;
private static final int PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 4001;
JSONArray jsonArray = new JSONArray();
private JSONArray jsonArray = new JSONArray();
private LocationManager locationManager;
private static final int LOCATION_UPDATE_INTERVAL = 1000;
double mLatitude = 0;
double mLongitude = 0;
private double mLatitude = 0;
private double mLongitude = 0;
// Radius of the Earth in meters
private static final double EARTH_RADIUS = 6371000.0;
private final double EARTH_RADIUS = 6371000.0;
private Location previousLocation;
double mSpeed = 0;
private double mSpeed = 0;
private int orientationCount = 0, touchCount = 0;
final long REFRESH_TIME = 100; // miliseconds
// ===========================================================
// Methods for/from SuperClass/Interfaces
......@@ -103,6 +107,8 @@ public class TelematicsActivity extends Activity implements View.OnClickListener
mTvAvgVelocity = findViewById(R.id.tv_avg);
mTvRecordsSaved = findViewById(R.id.tv_records);
mIvBack.setOnClickListener(this);
mTvOrientationCount = findViewById(R.id.tv_orientation);
mTvTouchCount = findViewById(R.id.tv_touch);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
previousLocation = null;
......@@ -192,6 +198,13 @@ public class TelematicsActivity extends Activity implements View.OnClickListener
mIsTripStarted = false;
mTvTripButton.setText(R.string.cos_dlg_start_trip);
} else {
mTouchHandler = new Handler();
mTouchRunnable = new Runnable() {
@Override
public void run() {
mTouchHandler.postDelayed(this, REFRESH_TIME);
}
};
requestLocationUpdates();
registerSensor();
mIsTripStarted = true;
......@@ -239,22 +252,6 @@ public class TelematicsActivity extends Activity implements View.OnClickListener
// requestLocationUpdatePeriodically(location);
mLatitude = location.getLatitude();
mLongitude = location.getLongitude();
//TODO: similar implementation, comment all of the above blocks
// if (previousLocation != null) {
// // Calculate the distance traveled between the previous and current location
// float distance = previousLocation.distanceTo(location); // Distance in meters
//
// // Calculate the speed based on the distance traveled over a timeframe of x seconds
// float speed = distance / (LOCATION_UPDATE_INTERVAL / 1000); // Speed in meters/second
//
// // Convert speed to km/h
// float speedKmH = speed * 3.6f;
//
// mTvAvgVelocity.setText(String.format("%.1f", Math.floor(speedKmH)) + " km/h");
// }
//
// previousLocation = location;
}
@Override
......@@ -272,6 +269,40 @@ public class TelematicsActivity extends Activity implements View.OnClickListener
// Handle provider disabled if needed
}
@Override
public void onConfigurationChanged(@NotNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mIsTripStarted) {
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE || newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
orientationCount++;
mTvOrientationCount.setText(String.valueOf(orientationCount));
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// return super.onTouchEvent(event);
if (mIsTripStarted) {
// touchCount++;
// mTvTouchCount.setText(String.valueOf(touchCount));
// return true;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchCount++;
mTvTouchCount.setText(String.valueOf(touchCount));
mTouchHandler.post(mTouchRunnable);
return true;
case MotionEvent.ACTION_UP:
mTouchHandler.removeCallbacks(mTouchRunnable);
return true;
}
return false;
}
return false;
}
// ===========================================================
// Methods
// ===========================================================
......@@ -304,16 +335,16 @@ public class TelematicsActivity extends Activity implements View.OnClickListener
}
private void requestLocationUpdatePeriodically(Location location) {
mLoctionHandler = new Handler();
mLocationHandler = new Handler();
mLocationRunnable = new Runnable() {
@Override
public void run() {
double speed = calculateSpeed(mLatitude, mLongitude, location.getLatitude(), location.getLongitude(), (LOCATION_UPDATE_INTERVAL / 1000));
mTvAvgVelocity.setText(String.format("%.1f", Math.floor(speed)) + " km/h");
mLoctionHandler.postDelayed(this, LOCATION_UPDATE_INTERVAL);
mLocationHandler.postDelayed(this, LOCATION_UPDATE_INTERVAL);
}
};
mLoctionHandler.postDelayed(mLocationRunnable, LOCATION_UPDATE_INTERVAL);
mLocationHandler.postDelayed(mLocationRunnable, LOCATION_UPDATE_INTERVAL);
}
private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
......@@ -339,8 +370,8 @@ public class TelematicsActivity extends Activity implements View.OnClickListener
private void stopLocationUpdates() {
locationManager.removeUpdates(this);
if (mLoctionHandler != null)
mLoctionHandler.removeCallbacks(mLocationRunnable);
if (mLocationHandler != null)
mLocationHandler.removeCallbacks(mLocationRunnable);
}
private void registerSensor() {
......@@ -361,6 +392,8 @@ public class TelematicsActivity extends Activity implements View.OnClickListener
JSONObject jobjData = new JSONObject();
jobjData.putOpt("acceleration", mAcceleration);
jobjData.putOpt("speed", mSpeed);
jobjData.putOpt("orientation_count", orientationCount);
jobjData.putOpt("touch_count", touchCount);
jobj.putOpt(String.valueOf(System.currentTimeMillis()), jobjData);
mAccelerationTimestamps.add(jobj);
recordsCount[0]++;
......@@ -376,12 +409,16 @@ public class TelematicsActivity extends Activity implements View.OnClickListener
}
private void unregisterSensor() {
orientationCount = 0;
touchCount = 0;
mSensorManager.unregisterListener(this);
mTvVelocity.setText("0.0 km/h");
mTvAvgVelocity.setText("0.0 km/h");
Snackbar.make(mLlTelematicsMain, "Sensor Unregistered", Snackbar.LENGTH_SHORT).show();
if (mHandler != null)
mHandler.removeCallbacks(mRunnable);
if (mTouchHandler != null)
mTouchHandler.removeCallbacks(mTouchRunnable);
saveAccelerationDataToFile();
}
......@@ -393,37 +430,37 @@ public class TelematicsActivity extends Activity implements View.OnClickListener
}
//TODO: uncomment if needed to write to file
// if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
// != PackageManager.PERMISSION_GRANTED) {
// ActivityCompat.requestPermissions(this,
// new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
// PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
// } else {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
} else {
saveAccelerationDataToExternalStorage(jsonArray);
// }
}
}
private void saveAccelerationDataToExternalStorage(JSONArray jsonArray) {
//TODO: comment if needed to write to file
WarplyDBHelper.getInstance(this).saveTelematics(jsonArray);
// WarplyDBHelper.getInstance(this).saveTelematics(jsonArray);
//TODO: uncomment if needed to write to file
// String state = Environment.getExternalStorageState();
// if (Environment.MEDIA_MOUNTED.equals(state)) {
// File documentsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
// File file = new File(documentsDir, "telematics_data.json");
// try {
// FileOutputStream fileOutputStream = new FileOutputStream(file);
// fileOutputStream.write(jsonArray.toString().getBytes());
// fileOutputStream.close();
// Snackbar.make(mLlTelematicsMain, "Success saving data to file", Snackbar.LENGTH_SHORT).show();
// } catch (IOException e) {
// e.printStackTrace();
// Snackbar.make(mLlTelematicsMain, "Error saving acceleration data to file", Snackbar.LENGTH_SHORT).show();
// }
// } else {
// Snackbar.make(mLlTelematicsMain, "External storage is not accessible", Snackbar.LENGTH_SHORT).show();
// }
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
File documentsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
File file = new File(documentsDir, "telematics_data" + String.valueOf(System.currentTimeMillis()) + ".json");
try {
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(jsonArray.toString().getBytes());
fileOutputStream.close();
Snackbar.make(mLlTelematicsMain, "Success saving data to file", Snackbar.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
Snackbar.make(mLlTelematicsMain, "Error saving acceleration data to file", Snackbar.LENGTH_SHORT).show();
}
} else {
Snackbar.make(mLlTelematicsMain, "External storage is not accessible", Snackbar.LENGTH_SHORT).show();
}
}
// // Low-pass filter function using Exponential Moving Average (EMA)
......
......@@ -114,6 +114,59 @@
android:textSize="16sp" />
<TextView
android:id="@+id/tv_orientation_label"
fontPath="fonts/PeridotPE-Regular.ttf"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_marginTop="24dp"
android:layout_marginStart="24dp"
android:text="Orientation Count"
android:layout_below="@+id/tv_avg"
android:textColor="@color/blue_dark"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_orientation"
fontPath="fonts/PeridotPE-Bold.ttf"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_orientation_label"
android:layout_alignStart="@+id/tv_orientation_label"
android:layout_alignEnd="@+id/tv_orientation_label"
android:layout_marginTop="24dp"
android:gravity="center"
android:textColor="@color/blue_dark"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_touch_label"
fontPath="fonts/PeridotPE-Regular.ttf"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginEnd="24dp"
android:layout_alignParentEnd="true"
android:text="Touch Count"
android:layout_below="@+id/tv_avg"
android:layout_alignEnd="@+id/tv_orientation_label"
android:textColor="@color/blue_dark"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_touch"
fontPath="fonts/PeridotPE-Bold.ttf"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_touch_label"
android:layout_alignStart="@+id/tv_touch_label"
android:layout_alignEnd="@+id/tv_touch_label"
android:layout_marginTop="24dp"
android:gravity="center"
android:textColor="@color/blue_dark"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_records_label"
fontPath="fonts/PeridotPE-Regular.ttf"
android:layout_width="wrap_content"
......@@ -121,7 +174,7 @@
android:layout_centerHorizontal="true"
android:layout_marginTop="24dp"
android:text="Records Saved"
android:layout_below="@+id/tv_avg"
android:layout_below="@+id/tv_orientation"
android:textColor="@color/blue_dark"
android:textSize="16sp" />
......