Browse Source

Database Inserted

master
sipp11 5 years ago
parent
commit
573d3bc021
  1. 14
      app/build.gradle
  2. 81
      app/src/androidTest/java/co/zzyzx/sensorlogger/DatabaseTest.kt
  3. 20
      app/src/main/java/co/zzyzx/sensorlogger/Database.kt
  4. 103
      app/src/main/java/co/zzyzx/sensorlogger/EndlessService.kt
  5. 57
      app/src/main/java/co/zzyzx/sensorlogger/MainActivity.kt
  6. 43
      app/src/main/java/co/zzyzx/sensorlogger/db/Database.kt
  7. 29
      app/src/main/java/co/zzyzx/sensorlogger/db/dao.kt
  8. 15
      app/src/main/java/co/zzyzx/sensorlogger/db/entity.kt
  9. 10
      app/src/main/res/layout/activity_main.xml

14
app/build.gradle

@ -1,14 +1,14 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 28
defaultConfig {
applicationId "co.zzyzx.sensorlogger"
minSdkVersion 23
minSdkVersion 26
targetSdkVersion 28
versionCode 1
versionName "1.0"
@ -30,9 +30,17 @@ dependencies {
implementation 'com.github.kittinunf.fuel:fuel: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.exposed:exposed:0.16.1'
// Room dependencies
// implementation 'androidx.room:room-runtime:2.0.0'
// kapt 'androidx.room:room-compiler:2.0.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'
// implementation 'android.arch.lifecycle:extensions:1.1.1'
// kapt 'android.arch.lifecycle:compiler:1.1.1'
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'
}

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

@ -0,0 +1,81 @@
package co.zzyzx.sensorlogger
import android.arch.persistence.room.Room
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4
import co.zzyzx.sensorlogger.db.AppDatabase
import co.zzyzx.sensorlogger.db.Record
import co.zzyzx.sensorlogger.db.RecordDao
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import java.io.IOException
import java.time.Instant
@RunWith(AndroidJUnit4::class)
class DatabaseTest {
private lateinit var recordDao: RecordDao
private lateinit var db: AppDatabase
@Before
fun createDb() {
val appContext = InstrumentationRegistry.getTargetContext()
db = Room.inMemoryDatabaseBuilder(appContext, AppDatabase::class.java)
.allowMainThreadQueries()
.build()
recordDao = db.recordDao()
val records = arrayListOf(
Record(
timestamp = Instant.now().epochSecond,
sensor = "gps",
data = "123,23232"
),
Record(
timestamp = Instant.now().epochSecond,
sensor = "accelerometer",
data = "123,23232"
)
)
for (rec in records) {
recordDao.insertAll(rec)
}
}
@After
@Throws(IOException::class)
fun closeDb() {
db.close()
}
@Test
@Throws(Exception::class)
fun writeUserAndReadInList() {
val rec = Record(
timestamp = Instant.now().epochSecond,
sensor = "gps",
data = "333,32322"
)
recordDao.insertAll(rec)
val byName = recordDao.findBySensor("gps")
assertEquals(byName.data, rec.data)
assertEquals(byName.timestamp, rec.timestamp)
}
@Test
@Throws(Exception::class)
fun deleteRecord() {
val records = recordDao.getAll()
val total = records.size
// Delete one
recordDao.delete(records.get(0))
val totalAfterMinusOne = recordDao.getAll().size
assertEquals(total - 1, totalAfterMinusOne)
}
}

20
app/src/main/java/co/zzyzx/sensorlogger/Database.kt

@ -1,20 +0,0 @@
package co.zzyzx.sensorlogger
import org.jetbrains.exposed.dao.EntityID
import org.jetbrains.exposed.dao.IntEntity
import org.jetbrains.exposed.dao.IntEntityClass
import org.jetbrains.exposed.dao.IntIdTable
object Records : IntIdTable() {
val timestamp = datetime("timestamp")
val sensor = varchar("sensor", 20)
val data = text("data:")
}
class Record(id: EntityID<Int>) : IntEntity(id) {
companion object : IntEntityClass<Record>(Records)
var timestamp by Records.timestamp
var sensor by Records.sensor
var data by Records.data
}

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

@ -1,6 +1,5 @@
package co.zzyzx.sensorlogger
//import com.github.kittinunf.fuel.core.extensions.jsonBody
import android.app.*
import android.content.Context
import android.content.Intent
@ -19,6 +18,7 @@ import android.os.IBinder
import android.os.PowerManager
import android.provider.Settings
import android.widget.Toast
import co.zzyzx.sensorlogger.db.RecordRepository
import com.github.kittinunf.fuel.Fuel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
@ -29,32 +29,11 @@ import java.util.*
fun Double.format(digits: Int) = java.lang.String.format("%.${digits}f", this)
fun Float.format(digits: Int) = java.lang.String.format("%.${digits}f", this)
const val SENSOR_DELAY = SensorManager.SENSOR_DELAY_GAME
class EndlessService : Service(), SensorEventListener, LocationListener {
override fun onLocationChanged(result: Location) {
val txt =
"coords: ${result.longitude.format(4)}, ${result.latitude.format(4)} - ${result.time.toDouble().format(
0
)}"
log(txt)
val notification = createNotification(txt)
nm.notify(notificationId, notification)
}
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {
}
override fun onProviderEnabled(p0: String?) {
}
override fun onProviderDisabled(p0: String?) {
}
private var wakeLock: PowerManager.WakeLock? = null
private var isServiceStarted = false
private lateinit var nm: NotificationManager
@ -63,7 +42,10 @@ class EndlessService : Service(), SensorEventListener, LocationListener {
private lateinit var mSensorManager: SensorManager
private lateinit var mAccelerometer: Sensor
private lateinit var mLocationManager: LocationManager
private lateinit var mGyroscope: Sensor
private var mLocationManager: LocationManager? = null // need to do this because of permission
private lateinit var recRepo: RecordRepository
override fun onBind(intent: Intent): IBinder? {
log("Some component want to bind with the service")
@ -87,7 +69,8 @@ class EndlessService : Service(), SensorEventListener, LocationListener {
)
}
mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL)
mSensorManager.registerListener(this, mAccelerometer, SENSOR_DELAY)
mSensorManager.registerListener(this, mGyroscope, SENSOR_DELAY)
// by returning this we make sure the service is restarted if the system kills the service
return START_STICKY
@ -96,35 +79,40 @@ class EndlessService : Service(), SensorEventListener, LocationListener {
override fun onCreate() {
super.onCreate()
log("The service has been created".toUpperCase())
// database init
recRepo = RecordRepository(applicationContext)
// notification init
val notification = createNotification()
notification.flags = Notification.FLAG_ONGOING_EVENT
startForeground(notificationId, notification)
mSensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
mGyroscope = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
if (checkSelfPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
mLocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
mLocationManager.requestLocationUpdates(
mLocationManager?.requestLocationUpdates(
LocationManager.PASSIVE_PROVIDER,
2000, // 2-sec
2.toFloat(), // 2-meter
this
)
mLocationManager.requestLocationUpdates(
mLocationManager?.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
2000, // 2-sec
2.toFloat(), // 2-meter
this
)
log("ok permission to get location updates")
// log("ok permission to get location updates")
}
}
override fun onDestroy() {
super.onDestroy()
mSensorManager.unregisterListener(this)
mLocationManager.removeUpdates(this)
mLocationManager?.removeUpdates(this)
log("The service has been destroyed".toUpperCase())
Toast.makeText(this, "Service destroyed", Toast.LENGTH_SHORT).show()
}
@ -175,6 +163,39 @@ class EndlessService : Service(), SensorEventListener, LocationListener {
nm.cancelAll()
}
override fun onLocationChanged(result: Location) {
val notiText = "coords: ${result.longitude.format(4)}, ${result.latitude.format(4)}"
val txt = arrayOf(
result.time,
result.longitude.format(7),
result.latitude.format(7),
result.speed,
result.altitude,
result.bearing,
result.accuracy,
result.provider,
result.isFromMockProvider
).joinToString(",")
recRepo.addNewRecord("location", txt)
val notification = createNotification(notiText)
nm.notify(notificationId, notification)
}
override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) {
}
override fun onProviderEnabled(p0: String?) {
}
override fun onProviderDisabled(p0: String?) {
}
override fun onAccuracyChanged(p0: Sensor?, p1: Int) {
}
@ -185,7 +206,6 @@ class EndlessService : Service(), SensorEventListener, LocationListener {
when (evt.sensor?.type) {
Sensor.TYPE_ACCELEROMETER -> {
val accelLin = arrayOf(0.toDouble(), 0.toDouble(), 0.toDouble())
val alpha = 0.8f
accelGravity[0] = alpha * accelGravity[0] + (1 - alpha) * evt.values[0]
@ -194,13 +214,20 @@ class EndlessService : Service(), SensorEventListener, LocationListener {
accelLin[0] = evt.values[0] - accelGravity[0]
accelLin[1] = evt.values[1] - accelGravity[1]
accelLin[2] = evt.values[2] - accelGravity[2]
val txt =
"[accel] (${accelLin[0].format(3)}, ${accelLin[1].format(3)}, ${accelLin[2].format(
3
)})"
// val notification = createNotification(txt)
// nm.notify(notificationId, notification)
val txt = arrayOf(
accelLin[0].format(3),
accelLin[1].format(3),
accelLin[2].format(3)
).joinToString(",")
recRepo.addNewRecord("accelerometer", txt)
}
Sensor.TYPE_GYROSCOPE -> {
val txt = arrayOf(
evt.values[0].format(3),
evt.values[1].format(3),
evt.values[2].format(3)
).joinToString(",")
recRepo.addNewRecord("gyroscope", txt)
}
}
}

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

@ -1,19 +1,20 @@
package co.zzyzx.sensorlogger
//import co.zzyzx.sensorlogger.db.RecordDatabase
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.location.LocationManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.Button
import android.widget.Toast
import co.zzyzx.sensorlogger.db.RecordRepository
import kotlinx.android.synthetic.main.activity_main.*
@ -22,9 +23,15 @@ const val PERMISSION_LOCATION = 0
class MainActivity : AppCompatActivity(),
ActivityCompat.OnRequestPermissionsResultCallback {
private lateinit var recRepo: RecordRepository
private var handler = Handler()
private val millisDelay = 200L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// db init
recRepo = RecordRepository(applicationContext)
requestForNecessaryPermissions()
title = getString(R.string.app_name)
@ -43,23 +50,56 @@ class MainActivity : AppCompatActivity(),
}
}
ask_location_permission_button.let{
it.setOnClickListener { requestForNecessaryPermissions() }
ask_location_permission_button.let {
it.setOnClickListener {
val perms = arrayOf(Manifest.permission.ACCESS_FINE_LOCATION)
ActivityCompat.requestPermissions(
this, perms,
PERMISSION_LOCATION
)
}
}
updateCounter()
}
private fun UIStatusUpdates(hasLocPerm : Boolean = true) {
private fun updateCounter() {
val runnable = Runnable { updateCounter() }
val sensors = arrayOf("location", "accelerometer", "gyroscope")
var text = mutableListOf<String>("Status", "-------------------------------")
for (sensor in sensors) {
val count = recRepo.getRecordCount(sensor)
text.add("$sensor --- $count records")
}
status_textview.text = text.joinToString(System.getProperty("line.separator"))
handler.postDelayed(runnable, millisDelay)
}
private fun UIStatusUpdates(hasLocPerm: Boolean = true) {
val mLocationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
log("isLocationEnabled? ${mLocationManager.isLocationEnabled} - ${mLocationManager.allProviders.toString()}")
log("isLocationEnabled? ${mLocationManager.isLocationEnabled} - ${mLocationManager.allProviders}")
if (hasLocPerm && mLocationManager.isLocationEnabled) {
location_status_textview.text = "OK"
location_status_textview.setBackgroundColor(ContextCompat.getColor(applicationContext, R.color.green))
location_status_textview.setBackgroundColor(
ContextCompat.getColor(
applicationContext,
R.color.green
)
)
ask_location_permission_button.visibility = View.INVISIBLE
} else {
location_status_textview.text = "OFF"
location_status_textview.setBackgroundColor(ContextCompat.getColor(applicationContext, R.color.red))
location_status_textview.setBackgroundColor(
ContextCompat.getColor(
applicationContext,
R.color.red
)
)
ask_location_permission_button.visibility = View.VISIBLE
}
}
@ -71,7 +111,6 @@ class MainActivity : AppCompatActivity(),
)
!= PackageManager.PERMISSION_GRANTED
) {
ask_location_permission_button.visibility = View.INVISIBLE
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(

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

@ -0,0 +1,43 @@
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 co.zzyzx.sensorlogger.log
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.time.Instant
@Database(entities = arrayOf(Record::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun recordDao(): RecordDao
}
class RecordRepository {
private var DB_NAME = "db_sensor_recs"
var db: AppDatabase
private var dao: RecordDao
constructor(context: Context) {
db = Room.databaseBuilder(context, AppDatabase::class.java, DB_NAME)
.allowMainThreadQueries()
.build()
dao = db.recordDao()
}
fun addNewRecord(sensor: String, data: String) {
val now = Instant.now().toEpochMilli()
GlobalScope.launch {
log("add [${now}] ${sensor} - ${data}")
dao.insertAll(Record(timestamp = now, sensor = sensor, data = data))
}
}
fun getRecordCount(sensor: String): Int {
return dao.getCount(sensor)
}
}

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

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

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

@ -0,0 +1,15 @@
package co.zzyzx.sensorlogger.db
import android.arch.persistence.room.ColumnInfo
import android.arch.persistence.room.Entity
import android.arch.persistence.room.Index
import android.arch.persistence.room.PrimaryKey
@Entity(indices = [(Index(value = ["timestamp", "sensor"], unique = true))])
data class Record(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "timestamp") val timestamp: Long,
@ColumnInfo(name = "sensor") val sensor: String?,
@ColumnInfo(name = "data") val data: String?
)

10
app/src/main/res/layout/activity_main.xml

@ -7,11 +7,6 @@
tools:context=".MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Status" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -63,4 +58,9 @@
android:text="Stop Foreground Service" />
</LinearLayout>
<TextView
android:id="@+id/status_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
Loading…
Cancel
Save