Compare commits

...

4 Commits

  1. 43
      app/build.gradle
  2. 14
      app/src/androidTest/java/co/zzyzx/sensorlogger/DatabaseTest.kt
  3. 9
      app/src/androidTest/java/co/zzyzx/sensorlogger/ExampleInstrumentedTest.kt
  4. 39
      app/src/main/AndroidManifest.xml
  5. 30
      app/src/main/java/co/zzyzx/sensorlogger/ActivityTransitionIntentService.kt
  6. 109
      app/src/main/java/co/zzyzx/sensorlogger/EndlessService.kt
  7. 21
      app/src/main/java/co/zzyzx/sensorlogger/MainActivity.kt
  8. 18
      app/src/main/java/co/zzyzx/sensorlogger/db/Database.kt
  9. 11
      app/src/main/java/co/zzyzx/sensorlogger/db/dao.kt
  10. 8
      app/src/main/java/co/zzyzx/sensorlogger/db/entity.kt

43
app/build.gradle

@ -12,7 +12,11 @@ android {
targetSdkVersion 28 targetSdkVersion 28
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// The following argument makes the Android Test Orchestrator run its
// "pm clear" command after each test invocation. This command ensures
// that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true'
} }
buildTypes { buildTypes {
release { release {
@ -20,29 +24,44 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} }
} }
// Gradle automatically adds 'android.test.runner' as a dependency.
// useLibrary 'android.test.runner'
// useLibrary 'android.test.base'
// useLibrary 'android.test.mock'
//
// testOptions {
// execution 'ANDROIDX_TEST_ORCHESTRATOR'
// }
} }
dependencies { dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar']) implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3' // implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.github.kittinunf.fuel:fuel:2.1.0' implementation 'com.github.kittinunf.fuel:fuel:2.1.0'
implementation 'com.github.kittinunf.fuel:fuel-android:2.1.0' implementation 'com.github.kittinunf.fuel:fuel-android:2.1.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0-M2' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0-M2'
// Room dependencies // Room dependencies
// implementation 'androidx.room:room-runtime:2.0.0' implementation 'androidx.room:room-runtime:2.1.0'
// kapt 'androidx.room:room-compiler:2.0.0' kapt 'androidx.room:room-compiler:2.1.0'
implementation 'android.arch.persistence.room:runtime:1.1.1'
annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'
kapt 'android.arch.persistence.room:compiler:1.1.1'
// activity recognition
implementation 'com.google.android.gms:play-services-location:17.0.0'
implementation 'com.opencsv:opencsv:4.0' implementation 'com.opencsv:opencsv:4.0'
// implementation 'android.arch.lifecycle:excompile 'com.opencsv:opencsv:4.0'tensions:1.1.1'
// kapt 'android.arch.lifecycle:compiler:1.1.1'
// Required -- JUnit 4 framework
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
// Core library
androidTestImplementation 'androidx.test:core:1.2.0'
// AndroidJUnitRunner and JUnit Rules
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test:rules:1.2.0'
// Assertions
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
} }

14
app/src/androidTest/java/co/zzyzx/sensorlogger/DatabaseTest.kt

@ -1,9 +1,9 @@
package co.zzyzx.sensorlogger package co.zzyzx.sensorlogger
import android.arch.persistence.room.Room import androidx.room.Room
import android.support.test.InstrumentationRegistry import androidx.test.ext.junit.runners.AndroidJUnit4
import android.support.test.runner.AndroidJUnit4 import androidx.test.platform.app.InstrumentationRegistry
import co.zzyzx.sensorlogger.db.AppDatabase import co.zzyzx.sensorlogger.db.AppDatabase
import co.zzyzx.sensorlogger.db.Record import co.zzyzx.sensorlogger.db.Record
import co.zzyzx.sensorlogger.db.RecordDao import co.zzyzx.sensorlogger.db.RecordDao
@ -23,7 +23,7 @@ class DatabaseTest {
@Before @Before
fun createDb() { fun createDb() {
val appContext = InstrumentationRegistry.getTargetContext() val appContext = InstrumentationRegistry.getInstrumentation().targetContext
db = Room.inMemoryDatabaseBuilder(appContext, AppDatabase::class.java) db = Room.inMemoryDatabaseBuilder(appContext, AppDatabase::class.java)
.allowMainThreadQueries() .allowMainThreadQueries()
.build() .build()
@ -41,9 +41,7 @@ class DatabaseTest {
data = "123,23232" data = "123,23232"
) )
) )
for (rec in records) { recordDao.insert(*records.toTypedArray())
recordDao.insertAll(rec)
}
} }
@After @After
@ -61,7 +59,7 @@ class DatabaseTest {
sensor = "gps", sensor = "gps",
data = "333,32322" data = "333,32322"
) )
recordDao.insertAll(rec) recordDao.insert(rec)
val byName = recordDao.findBySensor("gps") val byName = recordDao.findBySensor("gps")
assertEquals(byName.data, rec.data) assertEquals(byName.data, rec.data)
assertEquals(byName.timestamp, rec.timestamp) assertEquals(byName.timestamp, rec.timestamp)

9
app/src/androidTest/java/co/zzyzx/sensorlogger/ExampleInstrumentedTest.kt

@ -1,13 +1,12 @@
package co.zzyzx.sensorlogger package co.zzyzx.sensorlogger
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.junit.Assert.*
/** /**
* Instrumented test, which will execute on an Android device. * Instrumented test, which will execute on an Android device.
* *
@ -18,7 +17,7 @@ class ExampleInstrumentedTest {
@Test @Test
fun useAppContext() { fun useAppContext() {
// Context of the app under test. // Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext() val appContext = InstrumentationRegistry.getInstrumentation().targetContext
assertEquals("co.zzyzx.sensorlogger", appContext.packageName) assertEquals("co.zzyzx.sensorlogger", appContext.packageName)
} }
} }

39
app/src/main/AndroidManifest.xml

@ -1,12 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="co.zzyzx.sensorlogger"> package="co.zzyzx.sensorlogger">
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
<application <application
@ -20,21 +23,37 @@
<service <service
android:name=".EndlessService" android:name=".EndlessService"
android:enabled="true" android:enabled="true"
android:exported="false"> android:exported="false"></service>
</service>
<activity android:name=".MainActivity"> <activity android:name=".MainActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<receiver android:enabled="true" android:name=".StartReceiver"> <receiver
android:name=".StartReceiver"
android:enabled="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/> <action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- You don't need to include android:required="false" if your app's
minSdkVersion is 28 or higher. -->
<uses-library
android:name="android.test.runner"
android:required="false" />
<!-- For both of these declarations, you don't need to include
android:required="false" if your app's minSdkVersion is 28
or higher. -->
<uses-library
android:name="android.test.base"
android:required="false" />
<uses-library
android:name="android.test.mock"
android:required="false" />
</application> </application>

30
app/src/main/java/co/zzyzx/sensorlogger/ActivityTransitionIntentService.kt

@ -0,0 +1,30 @@
package co.zzyzx.sensorlogger
import android.app.IntentService
import android.content.Intent
import android.preference.PreferenceManager
import android.widget.Toast
import com.google.android.gms.location.ActivityTransitionResult
private const val TAG = "ActivityTransitionIS"
class ActivityTransitionIntentService : IntentService(TAG) {
override fun onHandleIntent(intent: Intent) {
val result = ActivityTransitionResult.extractResult(intent) as ActivityTransitionResult
val events = result.transitionEvents
var txt = ArrayList<String>(0)
for (evt in events) {
txt.add("${evt.activityType} - ${evt.transitionType}")
}
log("ACT_TRANSITION: ${events.joinToString(",")}")
Toast.makeText(applicationContext, events.joinToString(","), Toast.LENGTH_SHORT)
PreferenceManager.getDefaultSharedPreferences(this).edit()
.putString("ACTIVITY", txt.joinToString("|"))
.apply()
}
}

109
app/src/main/java/co/zzyzx/sensorlogger/EndlessService.kt

@ -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)

21
app/src/main/java/co/zzyzx/sensorlogger/MainActivity.kt

@ -4,17 +4,21 @@ import android.Manifest
import android.app.ActivityManager import android.app.ActivityManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.location.LocationManager import android.location.LocationManager
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment import android.os.Environment
import android.os.Handler import android.os.Handler
import android.support.v4.app.ActivityCompat import android.preference.Preference
import android.support.v4.content.ContextCompat import android.preference.PreferenceManager
import android.support.v7.app.AppCompatActivity
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import co.zzyzx.sensorlogger.db.RecordRepository import co.zzyzx.sensorlogger.db.RecordRepository
import com.opencsv.CSVWriter import com.opencsv.CSVWriter
import kotlinx.android.synthetic.main.activity_main.* import kotlinx.android.synthetic.main.activity_main.*
@ -23,13 +27,15 @@ import kotlinx.coroutines.launch
import java.io.File import java.io.File
import java.io.FileWriter import java.io.FileWriter
import java.time.Instant import java.time.Instant
import java.util.prefs.PreferenceChangeListener
const val PERMISSION_LOCATION = 0 const val PERMISSION_LOCATION = 0
const val WRITE_EXTERNAL_STORAGE = 1 const val WRITE_EXTERNAL_STORAGE = 1
class MainActivity : AppCompatActivity(), class MainActivity : AppCompatActivity(),
ActivityCompat.OnRequestPermissionsResultCallback { ActivityCompat.OnRequestPermissionsResultCallback,
SharedPreferences.OnSharedPreferenceChangeListener {
private lateinit var recRepo: RecordRepository private lateinit var recRepo: RecordRepository
private var handler = Handler() private var handler = Handler()
@ -333,4 +339,11 @@ class MainActivity : AppCompatActivity(),
} }
} }
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
if (key == "ACTIVITY") {
status_textview.text = PreferenceManager.getDefaultSharedPreferences(this).getString(key, "- Nah -")
}
}
} }

18
app/src/main/java/co/zzyzx/sensorlogger/db/Database.kt

@ -1,16 +1,15 @@
package co.zzyzx.sensorlogger.db package co.zzyzx.sensorlogger.db
import android.arch.persistence.room.Database
import android.arch.persistence.room.Room
import android.arch.persistence.room.RoomDatabase
import android.content.Context import android.content.Context
import co.zzyzx.sensorlogger.log import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.time.Instant import java.time.Instant
@Database(entities = arrayOf(Record::class), version = 1) @Database(entities = [Record::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
abstract fun recordDao(): RecordDao abstract fun recordDao(): RecordDao
} }
@ -31,8 +30,13 @@ class RecordRepository {
fun addNewRecord(sensor: String, data: String) { fun addNewRecord(sensor: String, data: String) {
val now = Instant.now().toEpochMilli() val now = Instant.now().toEpochMilli()
GlobalScope.launch { GlobalScope.launch {
log("add [${now}] ${sensor} - ${data}") dao.insert(Record(timestamp = now, sensor = sensor, data = data))
dao.insertAll(Record(timestamp = now, sensor = sensor, data = data)) }
}
fun addBulkRecord(recs: List<Record>) {
GlobalScope.launch {
dao.insert(*recs.toTypedArray())
} }
} }

11
app/src/main/java/co/zzyzx/sensorlogger/db/dao.kt

@ -1,7 +1,8 @@
package co.zzyzx.sensorlogger.db package co.zzyzx.sensorlogger.db
import android.arch.lifecycle.LiveData import androidx.lifecycle.LiveData
import android.arch.persistence.room.* import androidx.room.*
@Dao @Dao
interface RecordDao { interface RecordDao {
@ -12,18 +13,16 @@ interface RecordDao {
fun getAll(): List<Record> fun getAll(): List<Record>
@Query("SELECT * FROM record WHERE sensor LIKE :sensor ORDER BY timestamp DESC LIMIT 1") @Query("SELECT * FROM record WHERE sensor LIKE :sensor ORDER BY timestamp DESC LIMIT 1")
fun getLatestLiveData(sensor : String): LiveData<List<Record>> fun getLatestLiveData(sensor: String): LiveData<List<Record>>
@Query("SELECT * FROM record WHERE sensor LIKE :name ORDER BY timestamp DESC LIMIT 1") @Query("SELECT * FROM record WHERE sensor LIKE :name ORDER BY timestamp DESC LIMIT 1")
fun findBySensor(name: String): Record fun findBySensor(name: String): Record
@Insert(onConflict = OnConflictStrategy.REPLACE) @Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(vararg records: Record)
@Insert
fun insert(vararg records: Record) fun insert(vararg records: Record)
@Delete @Delete
fun delete(record: Record) fun delete(record: Record)

8
app/src/main/java/co/zzyzx/sensorlogger/db/entity.kt

@ -1,9 +1,9 @@
package co.zzyzx.sensorlogger.db package co.zzyzx.sensorlogger.db
import android.arch.persistence.room.ColumnInfo import androidx.room.ColumnInfo
import android.arch.persistence.room.Entity import androidx.room.Entity
import android.arch.persistence.room.Index import androidx.room.Index
import android.arch.persistence.room.PrimaryKey import androidx.room.PrimaryKey
@Entity(indices = [(Index(value = ["timestamp", "sensor"], unique = true))]) @Entity(indices = [(Index(value = ["timestamp", "sensor"], unique = true))])

Loading…
Cancel
Save