[go: nahoru, domu]

Add exercise/passive listener/health event APIs

Relnote: """Measure
      - Callback methods were updated to include the name of the
        callback: registerCallback -> registerMeasureCallback.
    Passive
      - Added Health Events APIs. The first supported Health Event is
        fall detection.
      - Moved to a new set of listener APIs:
        - The broadcast was replaced by the PassiveListenerService.
        - The existing listeners were replaced with a single listener:
          PassiveListenerCallback
    Exercise
      - ExerciseState.ENDED was added and will be used instead of the
        multiple existing end states, with an end reason used to specify
        why the exercise has ended.
      - ExerciseUpdate now delivers exercise state through
        ExerciseStateInfo which contains both the current state and an
        end reason if appropriate.
    Added experimental DataTypes
      - ELEVATION_LOSS
      - GOLF_SHOT_COUNT
"""

Test: ./gradlew :health:health-services-client:assemble
Bug: 227475943
Change-Id: I22c27d70ddfbd3f8164cff1eedea53f5d956a25f
diff --git a/health/health-services-client/src/main/java/androidx/health/services/client/data/HealthEvent.kt b/health/health-services-client/src/main/java/androidx/health/services/client/data/HealthEvent.kt
new file mode 100644
index 0000000..5f73d62
--- /dev/null
+++ b/health/health-services-client/src/main/java/androidx/health/services/client/data/HealthEvent.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.health.services.client.data
+
+import androidx.health.services.client.proto.DataProto
+import java.time.Instant
+
+/** Represents a user's health event. */
+public class HealthEvent(
+    /** Gets the type of event. */
+    public val type: Type,
+
+    /** Returns the time of the health event. */
+    public val eventTime: Instant,
+
+    /** Gets metrics associated to the event. */
+    public val metrics: Map<DataType, List<DataPoint>>,
+) {
+
+    /** Health event types. */
+    public class Type private constructor(public val id: Int, public val name: String) {
+
+        override fun equals(other: Any?): Boolean {
+            if (this === other) return true
+            if (other !is Type) return false
+            if (id != other.id) return false
+
+            return true
+        }
+
+        override fun hashCode(): Int = id
+
+        override fun toString(): String = name
+
+        internal fun toProto(): DataProto.HealthEvent.HealthEventType =
+            DataProto.HealthEvent.HealthEventType.forNumber(id)
+                ?: DataProto.HealthEvent.HealthEventType.HEALTH_EVENT_TYPE_UNKNOWN
+
+        public companion object {
+            /**
+             * The Health Event is unknown, or is represented by a value too new for this library
+             * version to parse.
+             */
+            @JvmField
+            public val UNKNOWN: Type = Type(0, "UNKNOWN")
+
+            /** Health Event signifying the device detected that the user fell. */
+            @JvmField
+            public val FALL_DETECTED: Type = Type(3, "FALL_DETECTED")
+
+            @JvmField
+            internal val VALUES: List<Type> = listOf(UNKNOWN, FALL_DETECTED)
+
+            internal fun fromProto(proto: DataProto.HealthEvent.HealthEventType): Type =
+                VALUES.firstOrNull { it.id == proto.number } ?: UNKNOWN
+        }
+    }
+
+    internal constructor(
+        proto: DataProto.HealthEvent
+    ) : this(
+        Type.fromProto(proto.type),
+        Instant.ofEpochMilli(proto.eventTimeEpochMs),
+        proto
+            .metricsList
+            .map { entry -> DataType(entry.dataType) to entry.dataPointsList.map { DataPoint(it) } }
+            .toMap()
+    )
+
+    internal val proto: DataProto.HealthEvent by lazy {
+        DataProto.HealthEvent.newBuilder()
+            .setType(type.toProto())
+            .setEventTimeEpochMs(eventTime.toEpochMilli())
+            .addAllMetrics(
+                metrics
+                    .map { entry ->
+                        DataProto.HealthEvent.MetricsEntry.newBuilder()
+                            .setDataType(entry.key.proto)
+                            .addAllDataPoints(entry.value.map { it.proto })
+                            .build()
+                    }
+                    .sortedBy { it.dataType.name } // Required to ensure equals() works
+            )
+            .build()
+    }
+}
\ No newline at end of file