|
|
@ -4,7 +4,6 @@ import android.app.* |
|
|
|
import android.content.Context |
|
|
|
import android.content.Context |
|
|
|
import android.content.Intent |
|
|
|
import android.content.Intent |
|
|
|
import android.content.pm.PackageManager |
|
|
|
import android.content.pm.PackageManager |
|
|
|
import android.graphics.Color |
|
|
|
|
|
|
|
import android.hardware.Sensor |
|
|
|
import android.hardware.Sensor |
|
|
|
import android.hardware.SensorEvent |
|
|
|
import android.hardware.SensorEvent |
|
|
|
import android.hardware.SensorEventListener |
|
|
|
import android.hardware.SensorEventListener |
|
|
@ -18,14 +17,14 @@ import android.os.IBinder |
|
|
|
import android.os.PowerManager |
|
|
|
import android.os.PowerManager |
|
|
|
import android.provider.Settings |
|
|
|
import android.provider.Settings |
|
|
|
import android.widget.Toast |
|
|
|
import android.widget.Toast |
|
|
|
|
|
|
|
import co.zzyzx.sensorlogger.db.Record |
|
|
|
import co.zzyzx.sensorlogger.db.RecordRepository |
|
|
|
import co.zzyzx.sensorlogger.db.RecordRepository |
|
|
|
import com.github.kittinunf.fuel.Fuel |
|
|
|
import com.github.kittinunf.fuel.Fuel |
|
|
|
import kotlinx.coroutines.Dispatchers |
|
|
|
import com.google.android.gms.location.* |
|
|
|
import kotlinx.coroutines.GlobalScope |
|
|
|
|
|
|
|
import kotlinx.coroutines.delay |
|
|
|
|
|
|
|
import kotlinx.coroutines.launch |
|
|
|
|
|
|
|
import java.text.SimpleDateFormat |
|
|
|
import java.text.SimpleDateFormat |
|
|
|
|
|
|
|
import java.time.Instant |
|
|
|
import java.util.* |
|
|
|
import java.util.* |
|
|
|
|
|
|
|
import kotlin.collections.ArrayList |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun Double.format(digits: Int) = java.lang.String.format("%.${digits}f", this) |
|
|
|
fun Double.format(digits: Int) = java.lang.String.format("%.${digits}f", this) |
|
|
@ -40,12 +39,24 @@ class EndlessService : Service(), SensorEventListener, LocationListener { |
|
|
|
private val notificationChannelId = "ENDLESS SERVICE CHANNEL" |
|
|
|
private val notificationChannelId = "ENDLESS SERVICE CHANNEL" |
|
|
|
private val notificationId = 1011 |
|
|
|
private val notificationId = 1011 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private lateinit var mActivityRecognitionClient: ActivityRecognitionClient |
|
|
|
private lateinit var mSensorManager: SensorManager |
|
|
|
private lateinit var mSensorManager: SensorManager |
|
|
|
private lateinit var mAccelerometer: Sensor |
|
|
|
private lateinit var mAccelerometer: Sensor |
|
|
|
private lateinit var mGyroscope: Sensor |
|
|
|
private lateinit var mGyroscope: Sensor |
|
|
|
|
|
|
|
|
|
|
|
private var mLocationManager: LocationManager? = null // need to do this because of permission |
|
|
|
private var mLocationManager: LocationManager? = null // need to do this because of permission |
|
|
|
private lateinit var recRepo: RecordRepository |
|
|
|
private lateinit var recRepo: RecordRepository |
|
|
|
|
|
|
|
private var dataTemp = ArrayList<Record>(0) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun addNewRecord(sensor: String, text: String) { |
|
|
|
|
|
|
|
if (dataTemp.size < 2000) { |
|
|
|
|
|
|
|
dataTemp.add(Record(Instant.now().toEpochMilli(), sensor, text)) |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
val toSave = dataTemp.clone() as List<Record> |
|
|
|
|
|
|
|
dataTemp.clear() |
|
|
|
|
|
|
|
recRepo.addBulkRecord(toSave) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
override fun onBind(intent: Intent): IBinder? { |
|
|
|
override fun onBind(intent: Intent): IBinder? { |
|
|
|
log("Some component want to bind with the service") |
|
|
|
log("Some component want to bind with the service") |
|
|
@ -68,10 +79,8 @@ class EndlessService : Service(), SensorEventListener, LocationListener { |
|
|
|
"with a null intent. It has been probably restarted by the system." |
|
|
|
"with a null intent. It has been probably restarted by the system." |
|
|
|
) |
|
|
|
) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
mSensorManager.registerListener(this, mAccelerometer, SENSOR_DELAY) |
|
|
|
mSensorManager.registerListener(this, mAccelerometer, SENSOR_DELAY) |
|
|
|
mSensorManager.registerListener(this, mGyroscope, SENSOR_DELAY) |
|
|
|
mSensorManager.registerListener(this, mGyroscope, SENSOR_DELAY) |
|
|
|
|
|
|
|
|
|
|
|
// by returning this we make sure the service is restarted if the system kills the service |
|
|
|
// by returning this we make sure the service is restarted if the system kills the service |
|
|
|
return START_STICKY |
|
|
|
return START_STICKY |
|
|
|
} |
|
|
|
} |
|
|
@ -90,6 +99,7 @@ class EndlessService : Service(), SensorEventListener, LocationListener { |
|
|
|
mSensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager |
|
|
|
mSensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager |
|
|
|
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) |
|
|
|
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) |
|
|
|
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) |
|
|
|
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) |
|
|
|
|
|
|
|
setupActivityRecognitionUpdates() |
|
|
|
|
|
|
|
|
|
|
|
if (checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { |
|
|
|
if (checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { |
|
|
|
mLocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager |
|
|
|
mLocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager |
|
|
@ -109,7 +119,66 @@ class EndlessService : Service(), SensorEventListener, LocationListener { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun getActivityTransitionPendingIntent(): PendingIntent { |
|
|
|
|
|
|
|
val intent = Intent(this, ActivityTransitionIntentService::class.java) |
|
|
|
|
|
|
|
return PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private fun setupActivityRecognitionUpdates() { |
|
|
|
|
|
|
|
// ActivityRecognition |
|
|
|
|
|
|
|
val transitions = mutableListOf<ActivityTransition>() |
|
|
|
|
|
|
|
transitions += |
|
|
|
|
|
|
|
ActivityTransition.Builder() |
|
|
|
|
|
|
|
.setActivityType(DetectedActivity.IN_VEHICLE) |
|
|
|
|
|
|
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER) |
|
|
|
|
|
|
|
.build() |
|
|
|
|
|
|
|
/*transitions += |
|
|
|
|
|
|
|
ActivityTransition.Builder() |
|
|
|
|
|
|
|
.setActivityType(DetectedActivity.IN_VEHICLE) |
|
|
|
|
|
|
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT) |
|
|
|
|
|
|
|
.build()*/ |
|
|
|
|
|
|
|
transitions += |
|
|
|
|
|
|
|
ActivityTransition.Builder() |
|
|
|
|
|
|
|
.setActivityType(DetectedActivity.ON_BICYCLE) |
|
|
|
|
|
|
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER) |
|
|
|
|
|
|
|
.build() |
|
|
|
|
|
|
|
/*transitions += |
|
|
|
|
|
|
|
ActivityTransition.Builder() |
|
|
|
|
|
|
|
.setActivityType(DetectedActivity.ON_BICYCLE) |
|
|
|
|
|
|
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT) |
|
|
|
|
|
|
|
.build()*/ |
|
|
|
|
|
|
|
transitions += |
|
|
|
|
|
|
|
ActivityTransition.Builder() |
|
|
|
|
|
|
|
.setActivityType(DetectedActivity.WALKING) |
|
|
|
|
|
|
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER) |
|
|
|
|
|
|
|
.build() |
|
|
|
|
|
|
|
/*transitions += |
|
|
|
|
|
|
|
ActivityTransition.Builder() |
|
|
|
|
|
|
|
.setActivityType(DetectedActivity.WALKING) |
|
|
|
|
|
|
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_EXIT) |
|
|
|
|
|
|
|
.build()*/ |
|
|
|
|
|
|
|
transitions += |
|
|
|
|
|
|
|
ActivityTransition.Builder() |
|
|
|
|
|
|
|
.setActivityType(DetectedActivity.STILL) |
|
|
|
|
|
|
|
.setActivityTransition(ActivityTransition.ACTIVITY_TRANSITION_ENTER) |
|
|
|
|
|
|
|
.build() |
|
|
|
|
|
|
|
val request = ActivityTransitionRequest(transitions) |
|
|
|
|
|
|
|
val pendingIntent = getActivityTransitionPendingIntent() |
|
|
|
|
|
|
|
mActivityRecognitionClient = ActivityRecognition.getClient(applicationContext) |
|
|
|
|
|
|
|
val task = |
|
|
|
|
|
|
|
mActivityRecognitionClient.requestActivityTransitionUpdates(request, pendingIntent) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
task.addOnSuccessListener { log("ACT_TRANSITION: success listener") } |
|
|
|
|
|
|
|
task.addOnFailureListener { exception -> |
|
|
|
|
|
|
|
log("ACT_TRANSITION: failed $exception") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
override fun onDestroy() { |
|
|
|
override fun onDestroy() { |
|
|
|
|
|
|
|
if (dataTemp.size > 0) { |
|
|
|
|
|
|
|
recRepo.addBulkRecord(dataTemp) |
|
|
|
|
|
|
|
} |
|
|
|
super.onDestroy() |
|
|
|
super.onDestroy() |
|
|
|
mSensorManager.unregisterListener(this) |
|
|
|
mSensorManager.unregisterListener(this) |
|
|
|
mLocationManager?.removeUpdates(this) |
|
|
|
mLocationManager?.removeUpdates(this) |
|
|
@ -133,7 +202,7 @@ class EndlessService : Service(), SensorEventListener, LocationListener { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// we're starting a loop in a coroutine |
|
|
|
// we're starting a loop in a coroutine |
|
|
|
GlobalScope.launch(Dispatchers.IO) { |
|
|
|
/* GlobalScope.launch(Dispatchers.IO) { |
|
|
|
while (isServiceStarted) { |
|
|
|
while (isServiceStarted) { |
|
|
|
launch(Dispatchers.IO) { |
|
|
|
launch(Dispatchers.IO) { |
|
|
|
pingFakeServer() |
|
|
|
pingFakeServer() |
|
|
@ -141,7 +210,7 @@ class EndlessService : Service(), SensorEventListener, LocationListener { |
|
|
|
delay(1 * 180 * 1000) |
|
|
|
delay(1 * 180 * 1000) |
|
|
|
} |
|
|
|
} |
|
|
|
log("End of the loop for the service") |
|
|
|
log("End of the loop for the service") |
|
|
|
} |
|
|
|
} */ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun stopService() { |
|
|
|
private fun stopService() { |
|
|
@ -176,9 +245,9 @@ class EndlessService : Service(), SensorEventListener, LocationListener { |
|
|
|
result.accuracy, |
|
|
|
result.accuracy, |
|
|
|
result.provider, |
|
|
|
result.provider, |
|
|
|
result.isFromMockProvider |
|
|
|
result.isFromMockProvider |
|
|
|
).joinToString(",") |
|
|
|
).joinToString(",") |
|
|
|
|
|
|
|
|
|
|
|
recRepo.addNewRecord("location", txt) |
|
|
|
addNewRecord("location", txt) |
|
|
|
val notification = createNotification(notiText) |
|
|
|
val notification = createNotification(notiText) |
|
|
|
nm.notify(notificationId, notification) |
|
|
|
nm.notify(notificationId, notification) |
|
|
|
} |
|
|
|
} |
|
|
@ -219,7 +288,7 @@ class EndlessService : Service(), SensorEventListener, LocationListener { |
|
|
|
accelLin[1].format(3), |
|
|
|
accelLin[1].format(3), |
|
|
|
accelLin[2].format(3) |
|
|
|
accelLin[2].format(3) |
|
|
|
).joinToString(",") |
|
|
|
).joinToString(",") |
|
|
|
recRepo.addNewRecord("accelerometer", txt) |
|
|
|
addNewRecord("accelerometer", txt) |
|
|
|
} |
|
|
|
} |
|
|
|
Sensor.TYPE_GYROSCOPE -> { |
|
|
|
Sensor.TYPE_GYROSCOPE -> { |
|
|
|
val txt = arrayOf( |
|
|
|
val txt = arrayOf( |
|
|
@ -227,7 +296,8 @@ class EndlessService : Service(), SensorEventListener, LocationListener { |
|
|
|
evt.values[1].format(3), |
|
|
|
evt.values[1].format(3), |
|
|
|
evt.values[2].format(3) |
|
|
|
evt.values[2].format(3) |
|
|
|
).joinToString(",") |
|
|
|
).joinToString(",") |
|
|
|
recRepo.addNewRecord("gyroscope", txt) |
|
|
|
|
|
|
|
|
|
|
|
addNewRecord("gyroscope", txt) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -256,7 +326,8 @@ class EndlessService : Service(), SensorEventListener, LocationListener { |
|
|
|
val (bytes, error) = result |
|
|
|
val (bytes, error) = result |
|
|
|
if (bytes != null) { |
|
|
|
if (bytes != null) { |
|
|
|
log("[response bytes] ${String(bytes)}") |
|
|
|
log("[response bytes] ${String(bytes)}") |
|
|
|
val notification = createNotification("[req] ${gmtTime} - ${String(bytes)}") |
|
|
|
val notification = |
|
|
|
|
|
|
|
createNotification("[req] ${gmtTime} - ${String(bytes)}") |
|
|
|
nm.notify(notificationId, notification) |
|
|
|
nm.notify(notificationId, notification) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
log("[response error] ${error?.message}") |
|
|
|
log("[response error] ${error?.message}") |
|
|
@ -276,13 +347,13 @@ class EndlessService : Service(), SensorEventListener, LocationListener { |
|
|
|
val channel = NotificationChannel( |
|
|
|
val channel = NotificationChannel( |
|
|
|
notificationChannelId, |
|
|
|
notificationChannelId, |
|
|
|
"SL notifications channel", |
|
|
|
"SL notifications channel", |
|
|
|
NotificationManager.IMPORTANCE_DEFAULT |
|
|
|
NotificationManager.IMPORTANCE_LOW |
|
|
|
).let { |
|
|
|
).let { |
|
|
|
it.description = "SL Service channel" |
|
|
|
it.description = "SL Service channel" |
|
|
|
it.enableLights(true) |
|
|
|
it.enableLights(false) |
|
|
|
it.lightColor = Color.RED |
|
|
|
//it.lightColor = Color.RED |
|
|
|
it.enableVibration(true) |
|
|
|
it.enableVibration(false) |
|
|
|
it.vibrationPattern = longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400) |
|
|
|
//it.vibrationPattern = longArrayOf(100, 200, 300, 400, 500, 400, 300, 200, 400) |
|
|
|
it |
|
|
|
it |
|
|
|
} |
|
|
|
} |
|
|
|
nm.createNotificationChannel(channel) |
|
|
|
nm.createNotificationChannel(channel) |
|
|
|