1+ /*
2+ * Copyright 2026 The Android Open Source Project
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * https://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+ * See the License for the specific language governing permissions and
14+ * limitations under the License.
15+ */
16+
17+ package com.example.healthconnect
18+
19+ import android.os.Bundle
20+ import androidx.activity.ComponentActivity
21+ import androidx.activity.compose.setContent
22+ import androidx.activity.enableEdgeToEdge
23+ import androidx.compose.foundation.layout.Box
24+ import androidx.compose.foundation.layout.fillMaxSize
25+ import androidx.compose.foundation.layout.padding
26+ import androidx.compose.foundation.lazy.LazyColumn
27+ import androidx.compose.material3.Button
28+ import androidx.compose.material3.ExperimentalMaterial3Api
29+ import androidx.compose.material3.MaterialTheme
30+ import androidx.compose.material3.Scaffold
31+ import androidx.compose.material3.SnackbarHost
32+ import androidx.compose.material3.SnackbarHostState
33+ import androidx.compose.material3.Text
34+ import androidx.compose.material3.TopAppBar
35+ import androidx.compose.runtime.Composable
36+ import androidx.compose.runtime.remember
37+ import androidx.compose.runtime.rememberCoroutineScope
38+ import androidx.compose.ui.Alignment
39+ import androidx.compose.ui.Modifier
40+ import androidx.compose.ui.platform.LocalContext
41+ import androidx.compose.ui.text.style.TextAlign
42+ import androidx.compose.ui.unit.dp
43+ import androidx.health.connect.client.HealthConnectClient
44+ import com.example.healthconnect.ui.theme.SnippetsTheme
45+ import kotlinx.coroutines.launch
46+ import java.time.Clock
47+ import java.time.Instant
48+ import java.time.Duration
49+
50+ class HealthConnectActivity : ComponentActivity () {
51+ override fun onCreate (savedInstanceState : Bundle ? ) {
52+ super .onCreate(savedInstanceState)
53+ enableEdgeToEdge()
54+
55+ setContent {
56+ SnippetsTheme {
57+ HealthConnectScreen (Modifier .fillMaxSize())
58+ }
59+ }
60+ }
61+ }
62+
63+ @OptIn(ExperimentalMaterial3Api ::class )
64+ @Composable
65+ fun HealthConnectScreen (modifier : Modifier ) {
66+ val context = LocalContext .current
67+ val coroutineScope = rememberCoroutineScope()
68+ val snackbarHostState = remember { SnackbarHostState () }
69+
70+ // [START android_healthconnect_get_client]
71+ val availabilityStatus = HealthConnectClient .getSdkStatus(context)
72+ if (availabilityStatus == HealthConnectClient .SDK_UNAVAILABLE ) {
73+ Box (modifier = modifier.padding(16 .dp), contentAlignment = Alignment .Center ) {
74+ Text (
75+ text = " Health Connect is not available on this device. Please ensure it is installed and updated." ,
76+ style = MaterialTheme .typography.bodyLarge,
77+ textAlign = TextAlign .Center
78+ )
79+ }
80+ return
81+ }
82+
83+ val healthConnectClient = remember {
84+ if (availabilityStatus == HealthConnectClient .SDK_AVAILABLE ) {
85+ HealthConnectClient .getOrCreate(context)
86+ } else {
87+ null
88+ }
89+ }
90+ // [END android_healthconnect_get_client]
91+
92+ // Initialize our snippet manager
93+ val manager = remember(healthConnectClient) {
94+ healthConnectClient?.let { HealthConnectManager (it) }
95+ }
96+
97+ Scaffold (
98+ modifier = modifier,
99+ snackbarHost = { SnackbarHost (snackbarHostState) },
100+ topBar = { TopAppBar (title = { Text (" Health Connect Snippets" ) }) },
101+ ) { innerPadding ->
102+ LazyColumn (Modifier .padding(innerPadding).padding(horizontal = 16 .dp)) {
103+ item {
104+ Text (
105+ text = if (healthConnectClient != null )
106+ " Health Connect is available"
107+ else
108+ " Health Connect is not available" ,
109+ modifier = Modifier .padding(vertical = 16 .dp)
110+ )
111+ }
112+
113+ if (manager != null ) {
114+ item {
115+ Button (onClick = {
116+ coroutineScope.launch {
117+ val startTime = Instant .now().minusSeconds(3600 )
118+ val endTime = Instant .now()
119+ manager.insertSteps(startTime, endTime)
120+ snackbarHostState.showSnackbar(" Steps inserted!" )
121+ }
122+ }) {
123+ Text (" Run: Insert Steps" )
124+ }
125+ }
126+
127+ item {
128+ Button (
129+ modifier = Modifier .padding(top = 8 .dp),
130+ onClick = {
131+ coroutineScope.launch {
132+ val startTime = Instant .now().minus(Duration .ofDays(1 ))
133+ val endTime = Instant .now()
134+
135+ val total = manager.readStepsAggregate(startTime, endTime)
136+ snackbarHostState.showSnackbar(" Total Steps: $total " )
137+ }
138+ }) {
139+ Text (" Run: Read Steps Aggregate" )
140+ }
141+ }
142+ }
143+ }
144+ }
145+ }
0 commit comments