From b2970a92bc9e3f605c2462df01841956dada8d0f Mon Sep 17 00:00:00 2001 From: "Jack Boswell (boswelja)" Date: Fri, 18 Jun 2021 16:07:50 +1200 Subject: [PATCH 1/5] Create repeating suspendable function --- .../boswelja/watchconnection/wearos/Helpers.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/Helpers.kt diff --git a/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/Helpers.kt b/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/Helpers.kt new file mode 100644 index 00000000..fa364fcd --- /dev/null +++ b/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/Helpers.kt @@ -0,0 +1,15 @@ +package com.boswelja.watchconnection.wearos + +import kotlinx.coroutines.delay + +suspend fun repeating( + interval: Long, + initialDelay: Long = 0, + action: suspend () -> Unit +) { + delay(initialDelay) + while (true) { + action() + delay(interval) + } +} From 87fbe889709c8b86c282f8a477bf7256b13bf2f6 Mon Sep 17 00:00:00 2001 From: "Jack Boswell (boswelja)" Date: Fri, 18 Jun 2021 16:08:49 +1200 Subject: [PATCH 2/5] Switch getStatusFor to repeating checks, instead of listening to CapabilityClient --- .../wearos/WearOSDiscoveryPlatform.kt | 79 +++++++------------ 1 file changed, 30 insertions(+), 49 deletions(-) diff --git a/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt b/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt index 477eb2d6..d7eb441e 100644 --- a/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt +++ b/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt @@ -6,35 +6,35 @@ import com.boswelja.watchconnection.core.discovery.DiscoveryPlatform import com.boswelja.watchconnection.core.discovery.Status import com.boswelja.watchconnection.wearos.Constants.WEAROS_PLATFORM import com.google.android.gms.wearable.CapabilityClient -import com.google.android.gms.wearable.CapabilityInfo import com.google.android.gms.wearable.NodeClient import com.google.android.gms.wearable.Wearable import kotlinx.coroutines.CancellationException import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.channels.ProducerScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.runBlocking import kotlinx.coroutines.tasks.await class WearOSDiscoveryPlatform( private val appCapability: String, private val capabilities: List, private val nodeClient: NodeClient, - private val capabilityClient: CapabilityClient + private val capabilityClient: CapabilityClient, + private val scanRepeatInterval: Long = 2000 ) : DiscoveryPlatform { constructor( context: Context, appCapability: String, - capabilities: List + capabilities: List, + scanRepeatInterval: Long ) : this( appCapability, capabilities, Wearable.getNodeClient(context), - Wearable.getCapabilityClient(context) + Wearable.getCapabilityClient(context), + scanRepeatInterval ) override val platformIdentifier: String = WEAROS_PLATFORM @@ -102,52 +102,33 @@ class WearOSDiscoveryPlatform( } @ExperimentalCoroutinesApi - override fun getStatusFor(watchId: String): Flow = callbackFlow { + override fun getStatusFor(watchId: String): Flow = flow { // Start with CONNECTING - send(Status.CONNECTING) + emit(Status.CONNECTING) - // Create our listener - val listener = CapabilityClient.OnCapabilityChangedListener { info: CapabilityInfo -> - getStatusFromCapabilityInfo(watchId, info) - } - // Add the listener - capabilityClient.addListener(listener, appCapability) - - // Update capabilities now - val capabilityInfo = capabilityClient - .getCapability(appCapability, CapabilityClient.FILTER_ALL).await() - getStatusFromCapabilityInfo(watchId, capabilityInfo) - - // On finish, remove the listener - awaitClose { - capabilityClient.removeListener(listener) - } - } - - @ExperimentalCoroutinesApi - private fun ProducerScope.getStatusFromCapabilityInfo( - watchId: String, - info: CapabilityInfo - ) { - // If watch is found in capable nodes list, check if it's connected - if (info.nodes.any { it.id == watchId }) { - try { - // runBlocking should be safe here, since we're within a Flow - val connectedNodes = runBlocking { nodeClient.connectedNodes.await() } - // Got connected nodes, check if it contains our desired node - val node = connectedNodes.firstOrNull { it.id == watchId } - val status = node?.let { - if (node.isNearby) Status.CONNECTED_NEARBY - else Status.CONNECTED - } ?: Status.DISCONNECTED - trySend(status) - } catch (e: CancellationException) { - // Failed, send error - trySend(Status.ERROR) + // Get status at a set interval + repeating(interval = scanRepeatInterval) { + val capabilityInfo = capabilityClient + .getCapability(appCapability, CapabilityClient.FILTER_ALL).await() + if (capabilityInfo.nodes.any { it.id == watchId }) { + try { + // runBlocking should be safe here, since we're within a Flow + val connectedNodes = nodeClient.connectedNodes.await() + // Got connected nodes, check if it contains our desired node + val node = connectedNodes.firstOrNull { it.id == watchId } + val status = node?.let { + if (node.isNearby) Status.CONNECTED_NEARBY + else Status.CONNECTED + } ?: Status.DISCONNECTED + emit(status) + } catch (e: CancellationException) { + // Failed, send error + emit(Status.ERROR) + } + } else { + // No watch in capable nodes, app is missing + emit(Status.MISSING_APP) } - } else { - // No watch in capable nodes, app is missing - trySend(Status.MISSING_APP) } } } From 01aff16fd4c923c3b33bc92a76ad1e31b4268c15 Mon Sep 17 00:00:00 2001 From: "Jack Boswell (boswelja)" Date: Fri, 18 Jun 2021 16:12:34 +1200 Subject: [PATCH 3/5] Minor improvements to repeating function Also comment code --- .../com/boswelja/watchconnection/wearos/Helpers.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/Helpers.kt b/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/Helpers.kt index fa364fcd..74837f99 100644 --- a/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/Helpers.kt +++ b/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/Helpers.kt @@ -2,12 +2,21 @@ package com.boswelja.watchconnection.wearos import kotlinx.coroutines.delay -suspend fun repeating( +/** + * Schedule a suspendable code block to be executed at a regular interval. + * @param interval The interval in milliseconds to execute the code block after. Must be greater + * than 0. + * @param initialDelay The initial delay in milliseconds before first execution. Values less than or + * equal to 0 are ignored. + * @param action The suspendable code block to be executed. + */ +internal suspend fun repeating( interval: Long, initialDelay: Long = 0, action: suspend () -> Unit ) { - delay(initialDelay) + if (interval <= 0) throw IllegalArgumentException("interval must be greater than 0") + if (initialDelay > 0) delay(initialDelay) while (true) { action() delay(interval) From ef122b45edda6b2f7951080ef2184bce5e9dbdd6 Mon Sep 17 00:00:00 2001 From: "Jack Boswell (boswelja)" Date: Fri, 18 Jun 2021 16:13:52 +1200 Subject: [PATCH 4/5] Repeat flowing Capabilities --- .../wearos/WearOSDiscoveryPlatform.kt | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt b/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt index d7eb441e..0f05568a 100644 --- a/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt +++ b/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt @@ -88,17 +88,19 @@ class WearOSDiscoveryPlatform( } override fun getCapabilitiesFor(watchId: String): Flow> = flow { - val discoveredCapabilities = mutableListOf() - capabilities.forEach { capability -> - // Get capability info - val capabilityInfo = capabilityClient - .getCapability(capability, CapabilityClient.FILTER_ALL) - .await() - // If node is found with same ID as watch, emit capability - if (capabilityInfo.nodes.any { it.id == watchId }) - discoveredCapabilities += capabilityInfo.name + repeating(interval = scanRepeatInterval) { + val discoveredCapabilities = mutableListOf() + capabilities.forEach { capability -> + // Get capability info + val capabilityInfo = capabilityClient + .getCapability(capability, CapabilityClient.FILTER_ALL) + .await() + // If node is found with same ID as watch, emit capability + if (capabilityInfo.nodes.any { it.id == watchId }) + discoveredCapabilities += capabilityInfo.name + } + emit(discoveredCapabilities) } - emit(discoveredCapabilities) } @ExperimentalCoroutinesApi From 46473b202f344ca156c4c35bfac3d743f6f0d02d Mon Sep 17 00:00:00 2001 From: "Jack Boswell (boswelja)" Date: Fri, 18 Jun 2021 16:14:31 +1200 Subject: [PATCH 5/5] Repeat flowing all watches --- .../wearos/WearOSDiscoveryPlatform.kt | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt b/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt index 0f05568a..6dadd881 100644 --- a/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt +++ b/wearos/src/main/kotlin/com/boswelja/watchconnection/wearos/WearOSDiscoveryPlatform.kt @@ -40,15 +40,17 @@ class WearOSDiscoveryPlatform( override val platformIdentifier: String = WEAROS_PLATFORM override fun allWatches(): Flow> = flow { - emit( - nodeClient.connectedNodes.await().map { node -> - Watch( - node.displayName, - node.id, - platformIdentifier - ) - } - ) + repeating(interval = scanRepeatInterval) { + emit( + nodeClient.connectedNodes.await().map { node -> + Watch( + node.displayName, + node.id, + platformIdentifier + ) + } + ) + } } @ExperimentalCoroutinesApi