[O] Split code into service
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||||
|
|
||||||
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
|
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />
|
||||||
|
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<service android:name=".MyService"/>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.hydev.wearsync
|
package org.hydev.wearsync
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.app.Service
|
||||||
import android.bluetooth.BluetoothManager
|
import android.bluetooth.BluetoothManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
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.InfluxDBClientKotlin
|
||||||
import com.influxdb.client.kotlin.InfluxDBClientKotlinFactory
|
import com.influxdb.client.kotlin.InfluxDBClientKotlinFactory
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
import kotlin.reflect.full.isSubclassOf
|
||||||
|
|
||||||
|
|
||||||
fun View.snack(msg: String) = Snackbar.make(this, msg, Snackbar.LENGTH_LONG)
|
fun View.snack(msg: String) = Snackbar.make(this, msg, Snackbar.LENGTH_LONG)
|
||||||
@@ -62,8 +64,15 @@ val Context.prefs get() = object : Prefs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : Activity> Context.intent() = Intent(this, T::class.java)
|
inline fun <reified T> Context.intent() = Intent(this, T::class.java)
|
||||||
inline fun <reified T : Activity> Context.act() = startActivity(intent<T>())
|
inline fun <reified T> Context.act()
|
||||||
|
{
|
||||||
|
if (T::class.isSubclassOf(Activity::class))
|
||||||
|
startActivity(intent<T>())
|
||||||
|
else if (T::class.isSubclassOf(Service::class))
|
||||||
|
startService(intent<T>())
|
||||||
|
else TODO("Unimplemented: ${T::class}")
|
||||||
|
}
|
||||||
fun ComponentActivity.actCallback(fn: ActivityResultCallback<ActivityResult>) =
|
fun ComponentActivity.actCallback(fn: ActivityResultCallback<ActivityResult>) =
|
||||||
registerForActivityResult(ActivityResultContracts.StartActivityForResult(), fn)
|
registerForActivityResult(ActivityResultContracts.StartActivityForResult(), fn)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package org.hydev.wearsync
|
package org.hydev.wearsync
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.NotificationChannel
|
||||||
|
import android.app.NotificationManager
|
||||||
import android.bluetooth.BluetoothAdapter
|
import android.bluetooth.BluetoothAdapter
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
@@ -13,15 +15,18 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.influxdb.client.kotlin.InfluxDBClientKotlin
|
import com.influxdb.client.kotlin.InfluxDBClientKotlin
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.channels.Channel
|
|
||||||
import kotlinx.coroutines.flow.consumeAsFlow
|
|
||||||
import org.hydev.wearsync.ActivityPermissions.Companion.hasPermissions
|
import org.hydev.wearsync.ActivityPermissions.Companion.hasPermissions
|
||||||
import org.hydev.wearsync.bles.BluetoothHandler.Companion.ble
|
|
||||||
import org.hydev.wearsync.databinding.ActivityMainBinding
|
import org.hydev.wearsync.databinding.ActivityMainBinding
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class MainActivity : AppCompatActivity()
|
class MainActivity : AppCompatActivity()
|
||||||
{
|
{
|
||||||
|
companion object {
|
||||||
|
var instance: MainActivity? = null
|
||||||
|
}
|
||||||
|
|
||||||
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
||||||
|
|
||||||
lateinit var binding: ActivityMainBinding
|
lateinit var binding: ActivityMainBinding
|
||||||
lateinit var influx: InfluxDBClientKotlin
|
lateinit var influx: InfluxDBClientKotlin
|
||||||
|
|
||||||
@@ -41,15 +46,24 @@ class MainActivity : AppCompatActivity()
|
|||||||
{
|
{
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
// Bind activity
|
||||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
setSupportActionBar(binding.toolbar)
|
setSupportActionBar(binding.toolbar)
|
||||||
|
|
||||||
|
// Create recycler
|
||||||
binding.content.recycler.let {
|
binding.content.recycler.let {
|
||||||
it.adapter = RecordAdapter(records)
|
it.adapter = RecordAdapter(records)
|
||||||
it.layoutManager = LinearLayoutManager(this)
|
it.layoutManager = LinearLayoutManager(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create notification channel
|
||||||
|
val chan = NotificationChannel(MyService.NOTIF_CHANNEL_ID, "Keep-alive Notification",
|
||||||
|
NotificationManager.IMPORTANCE_MIN)
|
||||||
|
getSysServ<NotificationManager>().createNotificationChannel(chan)
|
||||||
|
|
||||||
|
instance = this
|
||||||
|
|
||||||
if (!hasPermissions()) permissionCallback.launch(intent<ActivityPermissions>())
|
if (!hasPermissions()) permissionCallback.launch(intent<ActivityPermissions>())
|
||||||
else afterPermissions()
|
else afterPermissions()
|
||||||
}
|
}
|
||||||
@@ -83,7 +97,7 @@ class MainActivity : AppCompatActivity()
|
|||||||
binding.content.tvDevice.text = "Configured Device: ${prefs.chosenDevice}"
|
binding.content.tvDevice.text = "Configured Device: ${prefs.chosenDevice}"
|
||||||
binding.content.tvValue.text = "Service started!"
|
binding.content.tvValue.text = "Service started!"
|
||||||
|
|
||||||
startCollect()
|
act<MyService>()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume()
|
override fun onResume()
|
||||||
@@ -119,7 +133,6 @@ class MainActivity : AppCompatActivity()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
|
||||||
private val records = ArrayList<Any>()
|
private val records = ArrayList<Any>()
|
||||||
|
|
||||||
class RecordAdapter(val records: List<Any>) : RecyclerView.Adapter<RecordAdapter.ViewHolder>() {
|
class RecordAdapter(val records: List<Any>) : RecyclerView.Adapter<RecordAdapter.ViewHolder>() {
|
||||||
@@ -154,24 +167,4 @@ class MainActivity : AppCompatActivity()
|
|||||||
records.add(t)
|
records.add(t)
|
||||||
runOnUiThread { binding.content.recycler.adapter?.notifyDataSetChanged() }
|
runOnUiThread { binding.content.recycler.adapter?.notifyDataSetChanged() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun startCollect()
|
|
||||||
{
|
|
||||||
collect(ble.heartRateChannel)
|
|
||||||
collect(ble.batteryChannel)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <T : Any> collect(channel: Channel<T>) {
|
|
||||||
scope.launch {
|
|
||||||
channel.consumeAsFlow().collect {
|
|
||||||
try {
|
|
||||||
addRecord(it)
|
|
||||||
influx add it
|
|
||||||
}
|
|
||||||
catch (e: Exception) {
|
|
||||||
addRecord(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -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 <T : Any> collect(channel: Channel<T>) {
|
||||||
|
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"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user