Health: Ensure unregistering non-registered callback is a no-op.
This brings the implemention in line with the documentation and
intention.
Bug: 318429136
Bug: 318430531
Test: Unit tests passing.
Change-Id: I0f24916aa7af16d0bfb6ff5ab9e45a8c214aaf41
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedExerciseClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedExerciseClient.kt
index 8016126..3cd2656 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedExerciseClient.kt
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedExerciseClient.kt
@@ -171,14 +171,14 @@
executor)
}
+ @Suppress("UNCHECKED_CAST")
override fun clearUpdateCallbackAsync(
callback: ExerciseUpdateCallback
): ListenableFuture<Void> {
+ // Cast is unfortunately required as there is no non-null Void in Kotlin.
val listenerStub =
ExerciseUpdateListenerStub.ExerciseUpdateListenerCache.INSTANCE.remove(callback)
- ?: return Futures.immediateFailedFuture(
- IllegalArgumentException("Given listener was not added.")
- )
+ ?: return Futures.immediateFuture(null) as ListenableFuture<Void>
return unregisterListener(listenerStub.listenerKey) { service, resultFuture ->
service.clearUpdateListener(packageName, listenerStub, StatusCallback(resultFuture))
}
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedMeasureClient.kt b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedMeasureClient.kt
index 13bf8b2..a9fd73c 100644
--- a/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedMeasureClient.kt
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/impl/ServiceBackedMeasureClient.kt
@@ -89,15 +89,15 @@
executor)
}
+ @Suppress("UNCHECKED_CAST")
override fun unregisterMeasureCallbackAsync(
dataType: DeltaDataType<*, *>,
callback: MeasureCallback
): ListenableFuture<Void> {
+ // Cast is unfortunately required as there is no non-null Void in Kotlin.
val callbackStub =
MeasureCallbackCache.INSTANCE.remove(dataType, callback)
- ?: return Futures.immediateFailedFuture(
- IllegalArgumentException("Given callback was not registered.")
- )
+ ?: return Futures.immediateFuture(null) as ListenableFuture<Void>
val request = MeasureUnregistrationRequest(context.packageName, dataType)
return unregisterListener(callbackStub.listenerKey) { service, resultFuture ->
service.unregisterCallback(request, callbackStub, StatusCallback(resultFuture))
diff --git a/health/health-services-client/src/test/java/androidx/health/services/client/ExerciseClientTest.kt b/health/health-services-client/src/test/java/androidx/health/services/client/ExerciseClientTest.kt
index f463bc8..a6950d4 100644
--- a/health/health-services-client/src/test/java/androidx/health/services/client/ExerciseClientTest.kt
+++ b/health/health-services-client/src/test/java/androidx/health/services/client/ExerciseClientTest.kt
@@ -590,7 +590,6 @@
Shadows.shadowOf(Looper.getMainLooper()).idle()
statesList += (service.listener == null)
val deferred = async {
-
client.clearUpdateCallback(callback)
statesList += (service.listener == null)
}
@@ -602,6 +601,17 @@
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
@Test
+ fun clearUpdateCallback_nothingRegistered_noOp() = runTest {
+ val deferred = async {
+ client.clearUpdateCallback(callback)
+ }
+ advanceMainLooperIdle()
+
+ Truth.assertThat(deferred.await()).isNull()
+ }
+
+ @OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
+ @Test
fun addGoalToActiveExerciseShouldBeInvoked() = runTest {
val startExercise = async {
val exerciseConfig = ExerciseConfig(
diff --git a/health/health-services-client/src/test/java/androidx/health/services/client/MeasureClientTest.kt b/health/health-services-client/src/test/java/androidx/health/services/client/MeasureClientTest.kt
index 3b7411d..58b1b20 100644
--- a/health/health-services-client/src/test/java/androidx/health/services/client/MeasureClientTest.kt
+++ b/health/health-services-client/src/test/java/androidx/health/services/client/MeasureClientTest.kt
@@ -114,21 +114,13 @@
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
@Test
- fun unregisterCallbackSynchronously_throwsIllegalArgumentException() = runTest {
- var isExceptionCaught = false
-
+ fun unregisterCallbackSynchronously_callbackNotRegistered_success() = runTest {
val deferred = async {
- try {
- client.unregisterMeasureCallback(DataType.HEART_RATE_BPM, callback)
- } catch (e: IllegalArgumentException) {
- isExceptionCaught = true
- }
+ client.unregisterMeasureCallback(DataType.HEART_RATE_BPM, callback)
}
advanceMainLooperIdle()
- deferred.await()
- cleanup = false // Not registered
- Truth.assertThat(isExceptionCaught).isTrue()
+ Truth.assertThat(deferred.await()).isNull()
}
@OptIn(kotlinx.coroutines.ExperimentalCoroutinesApi::class)
diff --git a/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedExerciseClientTest.kt b/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedExerciseClientTest.kt
index d0afedb..5a483e59 100644
--- a/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedExerciseClientTest.kt
+++ b/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedExerciseClientTest.kt
@@ -114,6 +114,14 @@
}
@Test
+ fun clearUpdateCallbackAsync_callbackNotRegistered_noOp() {
+ val resultFuture = client.clearUpdateCallbackAsync(callback)
+ shadowOf(getMainLooper()).idle()
+
+ assertThat(resultFuture.get()).isNull()
+ }
+
+ @Test
fun dataTypeInAvailabilityCallbackShouldMatchRequested_justSampleType_startExercise() {
val exerciseConfig = ExerciseConfig(
ExerciseType.WALKING,
diff --git a/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedMeasureClientTest.kt b/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedMeasureClientTest.kt
index a8a7128..6d996a9 100644
--- a/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedMeasureClientTest.kt
+++ b/health/health-services-client/src/test/java/androidx/health/services/client/impl/ServiceBackedMeasureClientTest.kt
@@ -115,6 +115,15 @@
}
@Test
+ fun unregisterCallback_callbackNotRegistered_noOp() {
+ val resultFuture = client.unregisterMeasureCallbackAsync(HEART_RATE_BPM, callback)
+ shadowOf(Looper.getMainLooper()).idle()
+
+ assertThat(fakeService.unregisterEvents).isEmpty()
+ assertThat(resultFuture.get()).isNull()
+ }
+
+ @Test
fun dataPointsReachAppCallback() {
val event = MeasureCallbackEvent.createDataPointsUpdateEvent(
DataPointsResponse(