From aa4b6fd7d167f5fe8cb054e26219eb68b1436f49 Mon Sep 17 00:00:00 2001 From: Azalea Gui Date: Mon, 23 Jan 2023 22:50:31 -0500 Subject: [PATCH] [O] Split code into service --- app/src/main/AndroidManifest.xml | 2 + .../java/org/hydev/wearsync/Extensions.kt | 13 +++- .../java/org/hydev/wearsync/MainActivity.kt | 43 +++++------ .../main/java/org/hydev/wearsync/MyService.kt | 71 +++++++++++++++++++ 4 files changed, 102 insertions(+), 27 deletions(-) create mode 100644 app/src/main/java/org/hydev/wearsync/MyService.kt 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