diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 30cff04..3728edf 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
+
@@ -39,6 +40,7 @@
+
\ No newline at end of file
diff --git a/app/src/main/java/org/hydev/wearsync/Extensions.kt b/app/src/main/java/org/hydev/wearsync/Extensions.kt
index 05177a5..274a206 100644
--- a/app/src/main/java/org/hydev/wearsync/Extensions.kt
+++ b/app/src/main/java/org/hydev/wearsync/Extensions.kt
@@ -1,6 +1,7 @@
package org.hydev.wearsync
import android.app.Activity
+import android.app.Service
import android.bluetooth.BluetoothManager
import android.content.Context
import android.content.Intent
@@ -17,6 +18,7 @@ import com.influxdb.client.domain.WritePrecision
import com.influxdb.client.kotlin.InfluxDBClientKotlin
import com.influxdb.client.kotlin.InfluxDBClientKotlinFactory
import kotlin.reflect.KProperty
+import kotlin.reflect.full.isSubclassOf
fun View.snack(msg: String) = Snackbar.make(this, msg, Snackbar.LENGTH_LONG)
@@ -62,8 +64,15 @@ val Context.prefs get() = object : Prefs {
}
}
-inline fun Context.intent() = Intent(this, T::class.java)
-inline fun Context.act() = startActivity(intent())
+inline fun Context.intent() = Intent(this, T::class.java)
+inline fun Context.act()
+{
+ if (T::class.isSubclassOf(Activity::class))
+ startActivity(intent())
+ else if (T::class.isSubclassOf(Service::class))
+ startService(intent())
+ else TODO("Unimplemented: ${T::class}")
+}
fun ComponentActivity.actCallback(fn: ActivityResultCallback) =
registerForActivityResult(ActivityResultContracts.StartActivityForResult(), fn)
diff --git a/app/src/main/java/org/hydev/wearsync/MainActivity.kt b/app/src/main/java/org/hydev/wearsync/MainActivity.kt
index e2df39a..a3412a8 100644
--- a/app/src/main/java/org/hydev/wearsync/MainActivity.kt
+++ b/app/src/main/java/org/hydev/wearsync/MainActivity.kt
@@ -1,6 +1,8 @@
package org.hydev.wearsync
import android.annotation.SuppressLint
+import android.app.NotificationChannel
+import android.app.NotificationManager
import android.bluetooth.BluetoothAdapter
import android.content.Intent
import android.graphics.Color
@@ -13,15 +15,18 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.influxdb.client.kotlin.InfluxDBClientKotlin
import kotlinx.coroutines.*
-import kotlinx.coroutines.channels.Channel
-import kotlinx.coroutines.flow.consumeAsFlow
import org.hydev.wearsync.ActivityPermissions.Companion.hasPermissions
-import org.hydev.wearsync.bles.BluetoothHandler.Companion.ble
import org.hydev.wearsync.databinding.ActivityMainBinding
import java.util.*
class MainActivity : AppCompatActivity()
{
+ companion object {
+ var instance: MainActivity? = null
+ }
+
+ private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
+
lateinit var binding: ActivityMainBinding
lateinit var influx: InfluxDBClientKotlin
@@ -41,15 +46,24 @@ class MainActivity : AppCompatActivity()
{
super.onCreate(savedInstanceState)
+ // Bind activity
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
+ // Create recycler
binding.content.recycler.let {
it.adapter = RecordAdapter(records)
it.layoutManager = LinearLayoutManager(this)
}
+ // Create notification channel
+ val chan = NotificationChannel(MyService.NOTIF_CHANNEL_ID, "Keep-alive Notification",
+ NotificationManager.IMPORTANCE_MIN)
+ getSysServ().createNotificationChannel(chan)
+
+ instance = this
+
if (!hasPermissions()) permissionCallback.launch(intent())
else afterPermissions()
}
@@ -83,7 +97,7 @@ class MainActivity : AppCompatActivity()
binding.content.tvDevice.text = "Configured Device: ${prefs.chosenDevice}"
binding.content.tvValue.text = "Service started!"
- startCollect()
+ act()
}
override fun onResume()
@@ -119,7 +133,6 @@ class MainActivity : AppCompatActivity()
}
}
- private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
private val records = ArrayList()
class RecordAdapter(val records: List) : RecyclerView.Adapter() {
@@ -154,24 +167,4 @@ class MainActivity : AppCompatActivity()
records.add(t)
runOnUiThread { binding.content.recycler.adapter?.notifyDataSetChanged() }
}
-
- fun startCollect()
- {
- collect(ble.heartRateChannel)
- collect(ble.batteryChannel)
- }
-
- private fun collect(channel: Channel) {
- scope.launch {
- channel.consumeAsFlow().collect {
- try {
- addRecord(it)
- influx add it
- }
- catch (e: Exception) {
- addRecord(e)
- }
- }
- }
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/org/hydev/wearsync/MyService.kt b/app/src/main/java/org/hydev/wearsync/MyService.kt
new file mode 100644
index 0000000..2c450ea
--- /dev/null
+++ b/app/src/main/java/org/hydev/wearsync/MyService.kt
@@ -0,0 +1,71 @@
+package org.hydev.wearsync
+
+import android.app.PendingIntent
+import android.app.Service
+import android.content.Intent
+import androidx.core.app.NotificationCompat
+import com.influxdb.client.kotlin.InfluxDBClientKotlin
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.channels.Channel
+import kotlinx.coroutines.flow.consumeAsFlow
+import kotlinx.coroutines.launch
+import org.hydev.wearsync.bles.BluetoothHandler.Companion.ble
+
+class MyService : Service()
+{
+ private lateinit var influx: InfluxDBClientKotlin
+
+ private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
+
+ override fun onBind(intent: Intent?) = null
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int
+ {
+ influx = prefs.createInflux()
+ startCollect()
+
+ startForeground()
+ return super.onStartCommand(intent, flags, startId)
+ }
+
+ fun startCollect()
+ {
+ collect(ble.heartRateChannel)
+ collect(ble.batteryChannel)
+ }
+
+ private fun collect(channel: Channel) {
+ scope.launch {
+ channel.consumeAsFlow().collect {
+ try {
+ MainActivity.instance?.addRecord(it)
+ influx add it
+ }
+ catch (e: Exception) {
+ MainActivity.instance?.addRecord(e)
+ }
+ }
+ }
+ }
+
+ private fun startForeground()
+ {
+ val notificationIntent = Intent(this, MainActivity::class.java)
+ val pendingIntent = PendingIntent.getActivity(this, 0,
+ notificationIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
+ startForeground(NOTIF_ID, NotificationCompat.Builder(this, NOTIF_CHANNEL_ID)
+ .setOngoing(true)
+ .setSmallIcon(R.drawable.ic_watch_24)
+ .setContentTitle("🐱 Running!")
+ .setContentIntent(pendingIntent)
+ .build()
+ )
+ }
+
+ companion object
+ {
+ private const val NOTIF_ID = 1
+ const val NOTIF_CHANNEL_ID = "Channel_Id"
+ }
+}
\ No newline at end of file