Merge pull request #1910 from Andries-Smit/feat/wear-crashlytics
Feat Wear OS Crashlytics
This commit is contained in:
commit
2368300505
6 changed files with 141 additions and 13 deletions
app/src/main/java/info/nightscout/androidaps/plugins/general/wear/wearintegration
core/src/main/java/info/nightscout/androidaps/utils
shared/src/main/java/info/nightscout/shared/weardata
wear/src/main/java/info/nightscout/androidaps
|
@ -271,6 +271,13 @@ class DataHandlerMobile @Inject constructor(
|
||||||
aapsLogger.debug(LTag.WEAR, "SnoozeAlert received $it from ${it.sourceNodeId}")
|
aapsLogger.debug(LTag.WEAR, "SnoozeAlert received $it from ${it.sourceNodeId}")
|
||||||
alarmSoundServiceHelper.stopService(context, "Muted from wear")
|
alarmSoundServiceHelper.stopService(context, "Muted from wear")
|
||||||
}, fabricPrivacy::logException)
|
}, fabricPrivacy::logException)
|
||||||
|
disposable += rxBus
|
||||||
|
.toObservable(EventData.WearException::class.java)
|
||||||
|
.observeOn(aapsSchedulers.io)
|
||||||
|
.subscribe({
|
||||||
|
aapsLogger.debug(LTag.WEAR, "WearException received $it from ${it.sourceNodeId}")
|
||||||
|
fabricPrivacy.logWearException(it)
|
||||||
|
}, fabricPrivacy::logException)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleTddStatus() {
|
private fun handleTddStatus() {
|
||||||
|
|
|
@ -8,18 +8,13 @@ import dagger.android.AndroidInjection
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.database.AppRepository
|
import info.nightscout.androidaps.database.AppRepository
|
||||||
import info.nightscout.androidaps.events.EventMobileToWear
|
import info.nightscout.androidaps.events.EventMobileToWear
|
||||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
import info.nightscout.androidaps.interfaces.*
|
||||||
import info.nightscout.androidaps.interfaces.Config
|
|
||||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
|
||||||
import info.nightscout.androidaps.interfaces.Loop
|
|
||||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
import info.nightscout.androidaps.plugins.general.nsclient.data.NSDeviceStatus
|
||||||
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
|
import info.nightscout.androidaps.plugins.general.wear.WearPlugin
|
||||||
import info.nightscout.androidaps.plugins.general.wear.events.EventWearUpdateGui
|
import info.nightscout.androidaps.plugins.general.wear.events.EventWearUpdateGui
|
||||||
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
import info.nightscout.androidaps.receivers.ReceiverStatusStore
|
||||||
import info.nightscout.androidaps.utils.DefaultValueHelper
|
import info.nightscout.androidaps.utils.DefaultValueHelper
|
||||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||||
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
import info.nightscout.androidaps.utils.wizard.QuickWizard
|
||||||
|
@ -116,7 +111,7 @@ class DataLayerListenerServiceMobile : WearableListenerService() {
|
||||||
if (wearPlugin.isEnabled()) {
|
if (wearPlugin.isEnabled()) {
|
||||||
when (messageEvent.path) {
|
when (messageEvent.path) {
|
||||||
rxPath -> {
|
rxPath -> {
|
||||||
aapsLogger.debug(LTag.WEAR, "onMessageReceived: ${String(messageEvent.data)}")
|
aapsLogger.debug(LTag.WEAR, "onMessageReceived rxPath: ${String(messageEvent.data)}")
|
||||||
val command = EventData.deserialize(String(messageEvent.data))
|
val command = EventData.deserialize(String(messageEvent.data))
|
||||||
rxBus.send(command.also { it.sourceNodeId = messageEvent.sourceNodeId })
|
rxBus.send(command.also { it.sourceNodeId = messageEvent.sourceNodeId })
|
||||||
}
|
}
|
||||||
|
@ -203,4 +198,4 @@ class DataLayerListenerServiceMobile : WearableListenerService() {
|
||||||
|
|
||||||
const val WEAR_CAPABILITY = "androidaps_wear"
|
const val WEAR_CAPABILITY = "androidaps_wear"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,10 @@ import info.nightscout.androidaps.core.R
|
||||||
import info.nightscout.shared.logging.AAPSLogger
|
import info.nightscout.shared.logging.AAPSLogger
|
||||||
import info.nightscout.shared.logging.LTag
|
import info.nightscout.shared.logging.LTag
|
||||||
import info.nightscout.shared.sharedPreferences.SP
|
import info.nightscout.shared.sharedPreferences.SP
|
||||||
|
import info.nightscout.shared.weardata.EventData
|
||||||
|
import java.io.ByteArrayInputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.ObjectInputStream
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -79,7 +83,7 @@ class FabricPrivacy @Inject constructor(
|
||||||
|
|
||||||
// Crashlytics log message
|
// Crashlytics log message
|
||||||
fun logMessage(message: String) {
|
fun logMessage(message: String) {
|
||||||
aapsLogger.info(LTag.CORE,"Crashlytics log message: $message")
|
aapsLogger.info(LTag.CORE, "Crashlytics log message: $message")
|
||||||
FirebaseCrashlytics.getInstance().log(message)
|
FirebaseCrashlytics.getInstance().log(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,4 +96,31 @@ class FabricPrivacy @Inject constructor(
|
||||||
fun fabricEnabled(): Boolean {
|
fun fabricEnabled(): Boolean {
|
||||||
return sp.getBoolean(R.string.key_enable_fabric, true)
|
return sp.getBoolean(R.string.key_enable_fabric, true)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
fun logWearException(wearException: EventData.WearException) {
|
||||||
|
aapsLogger.debug(LTag.WEAR, "logWearException")
|
||||||
|
FirebaseCrashlytics.getInstance().apply {
|
||||||
|
setCustomKey("wear_exception", true)
|
||||||
|
setCustomKey("wear_board", wearException.board)
|
||||||
|
setCustomKey("wear_fingerprint", wearException.fingerprint)
|
||||||
|
setCustomKey("wear_sdk", wearException.sdk)
|
||||||
|
setCustomKey("wear_model", wearException.model)
|
||||||
|
setCustomKey("wear_manufacturer", wearException.manufacturer)
|
||||||
|
setCustomKey("wear_product", wearException.product)
|
||||||
|
}
|
||||||
|
logException(byteArrayToThrowable(wearException.exception))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun byteArrayToThrowable(wearExceptionData: ByteArray): Throwable {
|
||||||
|
val bis = ByteArrayInputStream(wearExceptionData)
|
||||||
|
try {
|
||||||
|
val ois = ObjectInputStream(bis)
|
||||||
|
return ois.readObject() as Throwable
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} catch (e: ClassNotFoundException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
return IllegalArgumentException("Wear Exception could not be de-serialized")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,6 +25,29 @@ sealed class EventData : Event() {
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ActionPong(val timeStamp: Long, val apiLevel: Int) : EventData()
|
data class ActionPong(val timeStamp: Long, val apiLevel: Int) : EventData()
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class WearException(
|
||||||
|
val timeStamp: Long,
|
||||||
|
val exception: ByteArray,
|
||||||
|
val board: String,
|
||||||
|
val fingerprint: String,
|
||||||
|
val sdk: String,
|
||||||
|
val model: String,
|
||||||
|
val manufacturer: String,
|
||||||
|
val product: String
|
||||||
|
) : EventData() {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean =
|
||||||
|
when (other) {
|
||||||
|
!is WearException -> false
|
||||||
|
else -> timeStamp == other.timeStamp && fingerprint == other.fingerprint
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return Objects.hash(timeStamp, fingerprint)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Error(val timeStamp: Long) : EventData() // ignored
|
data class Error(val timeStamp: Long) : EventData() // ignored
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import dagger.android.AndroidInjector
|
||||||
import dagger.android.DaggerApplication
|
import dagger.android.DaggerApplication
|
||||||
import info.nightscout.androidaps.comm.DataHandlerWear
|
import info.nightscout.androidaps.comm.DataHandlerWear
|
||||||
import info.nightscout.androidaps.comm.DataLayerListenerServiceWear
|
import info.nightscout.androidaps.comm.DataLayerListenerServiceWear
|
||||||
|
import info.nightscout.androidaps.comm.ExceptionHandlerWear
|
||||||
import info.nightscout.androidaps.di.DaggerWearComponent
|
import info.nightscout.androidaps.di.DaggerWearComponent
|
||||||
import info.nightscout.androidaps.events.EventWearPreferenceChange
|
import info.nightscout.androidaps.events.EventWearPreferenceChange
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
@ -21,13 +22,14 @@ class Aaps : DaggerApplication(), OnSharedPreferenceChangeListener {
|
||||||
@Inject lateinit var aapsLogger: AAPSLogger
|
@Inject lateinit var aapsLogger: AAPSLogger
|
||||||
@Inject lateinit var rxBus: RxBus
|
@Inject lateinit var rxBus: RxBus
|
||||||
@Inject lateinit var dataHandlerWear: DataHandlerWear // instantiate only
|
@Inject lateinit var dataHandlerWear: DataHandlerWear // instantiate only
|
||||||
|
@Inject lateinit var exceptionHandlerWear: ExceptionHandlerWear
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
super.onCreate()
|
super.onCreate()
|
||||||
|
exceptionHandlerWear.register()
|
||||||
aapsLogger.debug(LTag.WEAR, "onCreate")
|
aapsLogger.debug(LTag.WEAR, "onCreate")
|
||||||
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this)
|
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this)
|
||||||
startService(Intent(this, DataLayerListenerServiceWear::class.java))
|
startService(Intent(this, DataLayerListenerServiceWear::class.java))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun applicationInjector(): AndroidInjector<out DaggerApplication> =
|
override fun applicationInjector(): AndroidInjector<out DaggerApplication> =
|
||||||
|
@ -37,8 +39,8 @@ class Aaps : DaggerApplication(), OnSharedPreferenceChangeListener {
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
|
||||||
// we trigger update on Complications
|
// We trigger update on Complications
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(DataLayerListenerServiceWear.INTENT_NEW_DATA))
|
LocalBroadcastManager.getInstance(this).sendBroadcast(Intent(DataLayerListenerServiceWear.INTENT_NEW_DATA))
|
||||||
rxBus.send(EventWearPreferenceChange(key))
|
rxBus.send(EventWearPreferenceChange(key))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package info.nightscout.androidaps.comm
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import android.util.Log
|
||||||
|
import info.nightscout.androidaps.events.EventWearToMobile
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||||
|
import info.nightscout.shared.weardata.EventData
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.io.IOException
|
||||||
|
import java.io.ObjectOutputStream
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class ExceptionHandlerWear @Inject constructor(
|
||||||
|
private val rxBus: RxBus,
|
||||||
|
) {
|
||||||
|
|
||||||
|
private var mDefaultUEH: Thread.UncaughtExceptionHandler? = null
|
||||||
|
|
||||||
|
private val mWearUEH = Thread.UncaughtExceptionHandler { thread, ex ->
|
||||||
|
Log.d("WEAR", "uncaughtException :" + ex.message)
|
||||||
|
|
||||||
|
// Pass the exception to the bus which will send the data upstream to your Smartphone/Tablet
|
||||||
|
val wearException = EventData.WearException(
|
||||||
|
timeStamp = System.currentTimeMillis(),
|
||||||
|
exception = exceptionToByteArray(ex),
|
||||||
|
board = Build.BOARD,
|
||||||
|
sdk = Build.VERSION.SDK_INT.toString(),
|
||||||
|
fingerprint = Build.FINGERPRINT,
|
||||||
|
model = Build.MODEL,
|
||||||
|
manufacturer = Build.MANUFACTURER,
|
||||||
|
product = Build.PRODUCT
|
||||||
|
)
|
||||||
|
rxBus.send(EventWearToMobile(wearException))
|
||||||
|
|
||||||
|
// Let the default UncaughtExceptionHandler take it from here
|
||||||
|
mDefaultUEH?.uncaughtException(thread, ex)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun register() {
|
||||||
|
mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler()
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler(mWearUEH)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun exceptionToByteArray(ex: Throwable): ByteArray {
|
||||||
|
ex.stackTrace // Make sure the stacktrace gets built up
|
||||||
|
val bos = ByteArrayOutputStream()
|
||||||
|
var oos: ObjectOutputStream? = null
|
||||||
|
try {
|
||||||
|
oos = ObjectOutputStream(bos)
|
||||||
|
oos.writeObject(ex)
|
||||||
|
return bos.toByteArray()
|
||||||
|
|
||||||
|
} catch (e: IOException) {
|
||||||
|
e.printStackTrace()
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
oos?.close()
|
||||||
|
} catch (exx: IOException) {
|
||||||
|
// Ignore close exception
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
bos.close()
|
||||||
|
} catch (exx: IOException) {
|
||||||
|
// Ignore close exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return byteArrayOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue