diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8fb0dea2f6..89db45c95b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -208,6 +208,10 @@
android:host="*"
android:pathPrefix="@string/path_rx_bridge"
android:scheme="wear" />
+
{
- aapsLogger.debug(LTag.WEAR, "onMessageReceived: ${String(messageEvent.data)}")
+ rxPath -> {
+ aapsLogger.debug(LTag.WEAR, "onMessageReceived rxPath: ${String(messageEvent.data)}")
val command = EventData.deserialize(String(messageEvent.data))
rxBus.send(command.also { it.sourceNodeId = messageEvent.sourceNodeId })
}
+
+ exceptionPath -> logWearException(messageEvent)
}
}
}
+ private fun logWearException(messageEvent: MessageEvent) {
+ aapsLogger.debug(LTag.WEAR, "logWearException")
+ val map = DataMap.fromByteArray(messageEvent.data)
+ val bis = ByteArrayInputStream(map.getByteArray("exception"))
+ try {
+ val ois = ObjectInputStream(bis)
+ fabricPrivacy.getInstance().apply {
+ setCustomKey("wear_exception", true)
+ setCustomKey("wear_board", map.getString("board") ?: "unknown")
+ setCustomKey("wear_fingerprint", map.getString("fingerprint") ?: "unknown")
+ setCustomKey("wear_sdk", map.getString("sdk") ?: "unknown")
+ setCustomKey("wear_model", map.getString("model") ?: "unknown")
+ setCustomKey("wear_manufacturer", map.getString("manufacturer") ?: "unknown")
+ setCustomKey("wear_product", map.getString("product") ?: "unknown")
+ }
+ fabricPrivacy.logException(ois.readObject() as Throwable)
+ } catch (e: IOException) {
+ e.printStackTrace()
+ } catch (e: ClassNotFoundException) {
+ e.printStackTrace()
+ }
+ }
+
private var transcriptionNodeId: String? = null
private fun updateTranscriptionCapability() {
@@ -203,4 +227,4 @@ class DataLayerListenerServiceMobile : WearableListenerService() {
const val WEAR_CAPABILITY = "androidaps_wear"
}
-}
\ No newline at end of file
+}
diff --git a/core/src/main/java/info/nightscout/androidaps/utils/FabricPrivacy.kt b/core/src/main/java/info/nightscout/androidaps/utils/FabricPrivacy.kt
index e4ed8f77fa..7ec112ce9f 100644
--- a/core/src/main/java/info/nightscout/androidaps/utils/FabricPrivacy.kt
+++ b/core/src/main/java/info/nightscout/androidaps/utils/FabricPrivacy.kt
@@ -77,6 +77,10 @@ class FabricPrivacy @Inject constructor(
}
}
+ fun getInstance(): FirebaseCrashlytics {
+ return FirebaseCrashlytics.getInstance()
+ }
+
// Crashlytics log message
fun logMessage(message: String) {
aapsLogger.info(LTag.CORE,"Crashlytics log message: $message")
diff --git a/shared/src/main/res/values/wear_paths.xml b/shared/src/main/res/values/wear_paths.xml
index 36d7325849..defc5544a9 100644
--- a/shared/src/main/res/values/wear_paths.xml
+++ b/shared/src/main/res/values/wear_paths.xml
@@ -1,4 +1,5 @@
/rx_bridge
-
\ No newline at end of file
+ /wear_error
+
diff --git a/wear/src/main/AndroidManifest.xml b/wear/src/main/AndroidManifest.xml
index 3d10810e37..dba8a05295 100644
--- a/wear/src/main/AndroidManifest.xml
+++ b/wear/src/main/AndroidManifest.xml
@@ -537,6 +537,8 @@
android:resource="@drawable/quick_wizard_tile_preview" />
+
+
=
@@ -37,8 +38,8 @@ class Aaps : DaggerApplication(), OnSharedPreferenceChangeListener {
.build()
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))
rxBus.send(EventWearPreferenceChange(key))
}
-}
\ No newline at end of file
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionService.kt b/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionService.kt
new file mode 100644
index 0000000000..cc9964f142
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionService.kt
@@ -0,0 +1,110 @@
+package info.nightscout.androidaps.comm
+
+import android.app.IntentService
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.Handler
+import android.os.HandlerThread
+import android.util.Log
+import com.google.android.gms.tasks.Tasks
+import com.google.android.gms.wearable.CapabilityClient
+import com.google.android.gms.wearable.CapabilityInfo
+import com.google.android.gms.wearable.DataMap
+import com.google.android.gms.wearable.Node
+import com.google.android.gms.wearable.Wearable
+import info.nightscout.androidaps.R
+import java.io.ByteArrayOutputStream
+import java.io.IOException
+import java.io.ObjectOutputStream
+
+class ExceptionService : IntentService(ExceptionService::class.simpleName) {
+
+ private val messageClient by lazy { Wearable.getMessageClient(this) }
+ private val capabilityClient by lazy { Wearable.getCapabilityClient(this) }
+ private var handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
+ private val exceptionPath get() = getString(R.string.path_log_exception)
+ private var transcriptionNodeId: String? = null
+
+ override fun onCreate() {
+ super.onCreate()
+
+ handler.post { updateTranscriptionCapability() }
+ }
+
+ private fun updateTranscriptionCapability() {
+ val capabilityInfo: CapabilityInfo = Tasks.await(
+ capabilityClient.getCapability(DataLayerListenerServiceWear.PHONE_CAPABILITY, CapabilityClient.FILTER_REACHABLE)
+ )
+ Log.d("WEAR", "Nodes: ${capabilityInfo.nodes.joinToString(", ") { it.displayName + "(" + it.id + ")" }}")
+ pickBestNodeId(capabilityInfo.nodes)?.let { transcriptionNodeId = it }
+ Log.d("WEAR", "Selected node: $transcriptionNodeId")
+ }
+
+ // Find a nearby node or pick one arbitrarily
+ private fun pickBestNodeId(nodes: Set): String? =
+ nodes.firstOrNull { it.isNearby }?.id ?: nodes.firstOrNull()?.id
+
+ private fun sendMessage(path: String, data: ByteArray) {
+ transcriptionNodeId?.also { nodeId ->
+ messageClient
+ .sendMessage(nodeId, path, data).apply {
+ addOnSuccessListener { }
+ addOnFailureListener {
+ Log.d("WEAR", "sendMessage: $path failure")
+ }
+ }
+ }
+ }
+
+ override fun onHandleIntent(intent: Intent?) {
+ Log.d("WEAR", "onHandleIntent: ErrorService $intent")
+
+ val bos = ByteArrayOutputStream()
+ var oos: ObjectOutputStream? = null
+ try {
+ oos = ObjectOutputStream(bos)
+ oos.writeObject(intent?.getSerializableExtra("exception"))
+ val exceptionData = bos.toByteArray()
+ val dataMap = DataMap()
+
+ dataMap.putString("board", Build.BOARD)
+ dataMap.putString("sdk", Build.VERSION.SDK_INT.toString())
+ dataMap.putString("fingerprint", Build.FINGERPRINT)
+ dataMap.putString("model", Build.MODEL)
+ dataMap.putString("manufacturer", Build.MANUFACTURER)
+ dataMap.putString("product", Build.PRODUCT)
+ dataMap.putByteArray("exception", exceptionData)
+
+ handler.post {
+ sendMessage(exceptionPath, dataMap.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
+ }
+ }
+ }
+
+ init {
+ setIntentRedelivery(true)
+ }
+
+ companion object {
+ fun reportException(context: Context, ex: Throwable?) {
+ val errorIntent = Intent(context, ExceptionService::class.java)
+ errorIntent.putExtra("exception", ex)
+ context.startService(errorIntent)
+ }
+ }
+
+}
diff --git a/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionWear.kt b/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionWear.kt
new file mode 100644
index 0000000000..1bbc18ab8b
--- /dev/null
+++ b/wear/src/main/java/info/nightscout/androidaps/comm/ExceptionWear.kt
@@ -0,0 +1,23 @@
+package info.nightscout.androidaps.comm
+
+import android.content.Context
+import android.util.Log
+
+class ExceptionWear(private val context: Context) {
+
+ private var mDefaultUEH: Thread.UncaughtExceptionHandler? = null
+
+ private val mWearUEH = Thread.UncaughtExceptionHandler { thread, ex ->
+ Log.d("WEAR", "uncaughtException :" + ex.message)
+ // Pass the exception to a Service which will send the data upstream to your Smartphone/Tablet
+ ExceptionService.reportException(context, ex)
+ // Let the default UncaughtExceptionHandler take it from here
+ mDefaultUEH?.uncaughtException(thread, ex)
+ }
+
+ init {
+ mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler()
+ Thread.setDefaultUncaughtExceptionHandler(mWearUEH)
+ }
+
+}