Snap for 11383711 from 48a60a4390ad7915264c1982ae552f69c45270a9 to mainline-cellbroadcast-release

Change-Id: Ifcbd9b3d200005775ddaada88ef01d7ba13dfb5d
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 2ed54e6..b4672bf 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -57,6 +57,9 @@
       "name": "CtsHealthConnectHostSideDeviceTestCases"
     },
     {
+      "name": "CtsExerciseRouteTestCases"
+    },
+    {
       "name": "CtsHealthFitnessShowMigrationInfoIntentAbsentTests"
     }
   ]
diff --git a/apk/HealthPermissionsManifest.xml b/apk/HealthPermissionsManifest.xml
index 30c85b3..2574c78 100644
--- a/apk/HealthPermissionsManifest.xml
+++ b/apk/HealthPermissionsManifest.xml
@@ -53,8 +53,8 @@
         android:permissionGroup="android.permission-group.HEALTH" />
 
     <permission
-        android:name="android.permission.health.READ_EXERCISE_ROUTES_ALL"
-        android:label="@string/exercise_routes_all_read_content_description"
+        android:name="android.permission.health.READ_EXERCISE_ROUTES"
+        android:label="@string/exercise_routes_read_content_description"
         android:protectionLevel="dangerous"
         android:permissionGroup="android.permission-group.HEALTH" />
 
@@ -254,6 +254,12 @@
         android:protectionLevel="dangerous"
         android:permissionGroup="android.permission-group.HEALTH" />
 
+    <permission
+        android:name="android.permission.health.READ_SKIN_TEMPERATURE"
+        android:label="@string/skin_temperature_read_content_description"
+        android:protectionLevel="dangerous"
+        android:permissionGroup="android.permission-group.HEALTH" />
+
     <!-- Write permissions -->
     <!-- Write permissions for activities -->
     <permission
@@ -476,4 +482,10 @@
         android:label="@string/resting_heart_rate_write_content_description"
         android:protectionLevel="dangerous"
         android:permissionGroup="android.permission-group.HEALTH" />
+
+    <permission
+        android:name="android.permission.health.WRITE_SKIN_TEMPERATURE"
+        android:label="@string/skin_temperature_write_content_description"
+        android:protectionLevel="dangerous"
+        android:permissionGroup="android.permission-group.HEALTH" />
 </manifest>
diff --git a/apk/res/drawable/spinner_background.xml b/apk/res/drawable/spinner_background.xml
new file mode 100644
index 0000000..94b8cc7
--- /dev/null
+++ b/apk/res/drawable/spinner_background.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  Copyright (C) 2024 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.
+  -->
+
+<ripple
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="@color/settingslib_ripple_color">
+
+    <item android:id="@android:id/background">
+        <layer-list
+            android:paddingMode="stack"
+            android:paddingStart="0dp"
+            android:paddingEnd="24dp">
+            <item
+                android:top="8dp"
+                android:bottom="8dp">
+
+                <shape>
+                    <corners android:radius="28dp"/>
+                    <solid android:color="@android:color/system_accent1_100"/>
+                    <size android:height="@dimen/settingslib_spinner_height"/>
+                </shape>
+            </item>
+
+            <item
+                android:gravity="end"
+                android:top="15dp"
+                android:width="18dp"
+                android:height="18dp"
+                android:end="12dp"
+                android:drawable="@drawable/settingslib_arrow_drop_down"/>
+        </layer-list>
+    </item>
+</ripple>
diff --git a/apk/res/layout/item_data_entry.xml b/apk/res/layout/item_data_entry.xml
index 29f6788..26db8ec 100644
--- a/apk/res/layout/item_data_entry.xml
+++ b/apk/res/layout/item_data_entry.xml
@@ -48,7 +48,6 @@
         android:layout_weight="0"
         android:background="@null"
         android:padding="@dimen/spacing_normal"
-        android:contentDescription="@string/data_point_action_content_description"
         android:layout_gravity="center_vertical"
         android:src="?attr/deleteIcon"/>
 </LinearLayout>
diff --git a/apk/res/layout/item_exercise_session_entry.xml b/apk/res/layout/item_exercise_session_entry.xml
index 89eda9a..2b0c39f 100644
--- a/apk/res/layout/item_exercise_session_entry.xml
+++ b/apk/res/layout/item_exercise_session_entry.xml
@@ -120,7 +120,6 @@
             android:background="?android:attr/selectableItemBackground"
             android:minWidth="@dimen/two_target_min_width"
             android:minHeight="@dimen/two_target_min_width"
-            android:contentDescription="@string/data_point_action_content_description"
             android:src="?attr/deleteIcon"/>
     </LinearLayout>
 </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
diff --git a/apk/res/layout/item_heart_rate_entry.xml b/apk/res/layout/item_heart_rate_entry.xml
index 63eaa65..99ca61e 100644
--- a/apk/res/layout/item_heart_rate_entry.xml
+++ b/apk/res/layout/item_heart_rate_entry.xml
@@ -78,7 +78,6 @@
         android:minWidth="@dimen/two_target_min_width"
         android:gravity="center"
         android:padding="@dimen/spacing_normal"
-        android:contentDescription="@string/data_point_action_content_description"
         android:layout_gravity="center_vertical"
         android:src="?attr/deleteIcon"/>
 </LinearLayout>
\ No newline at end of file
diff --git a/apk/res/layout/item_sleep_session_entry.xml b/apk/res/layout/item_sleep_session_entry.xml
index 33fc6a8..eee0942 100644
--- a/apk/res/layout/item_sleep_session_entry.xml
+++ b/apk/res/layout/item_sleep_session_entry.xml
@@ -92,7 +92,6 @@
         android:minWidth="@dimen/two_target_min_width"
         android:gravity="center"
         android:padding="@dimen/spacing_normal"
-        android:contentDescription="@string/data_point_action_content_description"
         android:layout_gravity="center_vertical"
         android:src="?attr/deleteIcon"/>
 </LinearLayout>
\ No newline at end of file
diff --git a/apk/res/layout/route_request_dialog.xml b/apk/res/layout/route_request_dialog.xml
index 3d53d07..e4b29aa 100644
--- a/apk/res/layout/route_request_dialog.xml
+++ b/apk/res/layout/route_request_dialog.xml
@@ -18,15 +18,15 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:filterTouchesWhenObscured="true"
-    android:orientation="vertical"
-    android:paddingHorizontal="@dimen/spacing_large"
-    android:paddingBottom="@dimen/spacing_large"
-    android:paddingTop="@dimen/spacing_normal">
+    android:orientation="vertical">
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:orientation="vertical">
+        android:orientation="vertical"
+        android:paddingHorizontal="@dimen/spacing_large"
+        android:paddingBottom="@dimen/spacing_large"
+        android:paddingTop="@dimen/spacing_normal">
 
         <LinearLayout
             android:id="@+id/more_info"
@@ -111,12 +111,17 @@
 
             <Button
                 android:id="@+id/route_allow_button"
-                android:text="@string/request_permissions_allow"
+                android:text="@string/request_route_allow"
+                style="@style/PermissionGrantButtonTop" />
+
+            <Button
+                android:id="@+id/route_allow_all_button"
+                android:text="@string/request_route_allow_all"
                 style="@style/PermissionGrantButtonTop" />
 
             <Button
                 android:id="@+id/route_dont_allow_button"
-                android:text="@string/request_permissions_dont_allow"
+                android:text="@string/request_route_dont_allow"
                 style="@style/PermissionGrantButtonBottom" />
         </LinearLayout>
     </LinearLayout>
diff --git a/apk/res/layout/widget_app_source_layout.xml b/apk/res/layout/widget_app_source_layout.xml
index 82534b1..a33eee0 100644
--- a/apk/res/layout/widget_app_source_layout.xml
+++ b/apk/res/layout/widget_app_source_layout.xml
@@ -74,7 +74,7 @@
         android:id="@+id/action_icon"
         android:layout_width="0dp"
         android:layout_height="match_parent"
-        android:layout_weight="0.3"
+        android:layout_weight="0.32"
         android:minWidth="@dimen/button_size"
         android:layout_gravity="center_vertical">
 
@@ -82,6 +82,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="center_vertical|end"
+            android:longClickable="false"
             android:id="@+id/action_icon_background"
             android:minHeight="@dimen/icon_size"
             android:minWidth="@dimen/icon_size"
diff --git a/apk/res/values-af/strings.xml b/apk/res/values-af/strings.xml
index e540b63..ac0833e 100644
--- a/apk/res/values-af/strings.xml
+++ b/apk/res/values-af/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Hierdie data sluit inligting in soos tyd wat jy aktief is, soort oefening, rondtes, herhalings, sessies of swemhale"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Hierdie data sluit inligting in soos slaapfases en slaapsessies"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Sien alle inskrywings"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"verander"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Vee hierdie data uit"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"toegang tot jou gesondheiddata"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"oefenroete"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Skryf oefenroete"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Lees oefenroete"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Lees alle oefenroetes"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Afstand"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"afstand"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Lees afstand"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"rustende polsslag"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Lees rustende polsslag"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Skryf rustende polsslag"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Veltemperatuur"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"veltemperatuur"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Lees veltemperatuur"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Skryf veltemperatuur neer"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Laat “<xliff:g id="APP_NAME">%1$s</xliff:g>” toe om te lees"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Laat “<xliff:g id="APP_NAME">%1$s</xliff:g>” toe om te skryf"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Kanselleer"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Vee tans Health Connect-data uit"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Vee tans Health Connect-data uit"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Uitvee van data"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Vee data-inskrywing uit"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Vee inskrywing uit"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Vee data-inskrywing <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> uit"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Vee inskrywing <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> uit"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Totaal: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Skuif af"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Skuif na bo"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Skuif na onder"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Knoppie om <xliff:g id="SELECTED_APP">%s</xliff:g> van die prioriteitslys te verwyder"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Dubbeltik en sleep om te herrangskik"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fiksheid, welstand"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"toestemmings"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, gesondheiddata, gesondheidkategorieë, datatoegang, aktiwiteit, liggaamsmetings, siklusnasporing, voeding, slaap, lewensfunksies"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Net apps wat jy toegang tot jou oefenroetes gee"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Hoe kan ek toegang bestuur?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Jy kan apptoegang tot oefenroetes in Health Connect-instellings bestuur"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Terug"</string>
     <string name="loading" msgid="2526615755685950317">"Laai tans …"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integrasie is aan die gang"</string>
diff --git a/apk/res/values-am/strings.xml b/apk/res/values-am/strings.xml
index b106054..7fcec86 100644
--- a/apk/res/values-am/strings.xml
+++ b/apk/res/values-am/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"ይህ ውሂብ እንደ ገቢር የሆነበት ጊዜ፣ የልምምድ ዓይነት፣ ዙሮች፣ ድግግሞሾች፣ ክፍለ-ጊዜዎች ወይም የዋና ቀዘፋዎች ያለ መረጃን ያካትታል"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ይህ ውሂብ እንደ የእንቅልፍ ደረጃዎች እና የእንቅልፍ ክፍለ-ጊዜዎች ያለ መረጃን ያካትታል"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"ሁሉንም ግቤቶች አሳይ"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"ቀይር"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"ይህን ውሂብ ሰርዝ"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"የጤና አገናኝ"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"የጤና ውሂብዎን ይድረሱበት"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"የልምምድ መስመር"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"የልምምድ አቅጣጫን መጻፍ"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"የአካላዊ ልምምድ አቅጣጫን ያንብቡ"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"ሁሉንም የልምምድ መስመሮች ያንብቡ"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"ርቀት"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"ርቀት"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"ርቀትን ያነባል"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"የእረፍት ጊዜ የልብ ምት"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"የእረፍት ጊዜ የልብ ምትን ያነባል"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"የእረፍት ጊዜ የልብ ምትን ይጽፋል"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"የቆዳ ሙቀት መጠን"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"የቆዳ ሙቀት መጠን"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"የቆዳ ሙቀት መጠንን አንብብ"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"የቆዳ ሙቀት መጠንን ጻፍ"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"«<xliff:g id="APP_NAME">%1$s</xliff:g>» እንዲያነብ ይፍቀዱለት"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"«<xliff:g id="APP_NAME">%1$s</xliff:g>» እንዲጽፍ ይፍቀዱለት"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"ይቅር"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"የጤና አገናኝ ውሂብን በመሰረዝ ላይ"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"የጤና አገናኝ ውሂብን በመሰረዝ ላይ"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"የውሂብ ስረዛ"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"የውሂብ ግቤትን ሰርዝ"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"ግቤትን ሰርዝ"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"የውሂብ መግቢያን ሰርዝ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"መግቢያን ሰርዝ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"ጠቅላላ፦ <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 ዋ}one{# ዋ}other{# ዋ}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ዋት}one{# ዋት}other{# ዋት}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"ወደ ታች ውሰድ"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ወደ ራስጌ ውሰድ"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"ወደ ግርጌ ውሰድ"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"ከቅድሚያ ዝርዝር <xliff:g id="SELECTED_APP">%s</xliff:g> ማስወገጃ አዝራር"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"ዳግም ለመደርደር ሁለቴ መታ አድርገው ይጎትቱ"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"የአካል ብቃት፣ ጤናማነት"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"ፈቃዶች"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"የጤና አገናኝ፣ የጤና ውሂብ፣ የጤና ምድቦች፣ የውሂብ መዳረሻ፣ እንቅስቃሴ፣ የሰውነት አካል መለኪያዎች፣ የዑደት መከታተል፣ ስነ-ምግብ፣ እንቅልፍ፣ መሠረታዊ ነገሮች"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"እርስዎ የልምምድ መስመሮችዎን እንዲደርሱ የሚፈቅዱላቸው መተግበሪያዎች ብቻ"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"መዳረሻን እንዴት ማስተዳደር እችላለሁ?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"የልምምድ መስመሮችን የመተግበሪያ መዳረሻ በጤና አገናኝ ቅንብሮች ውስጥ ማስተዳደር ይችላሉ"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"ተመለስ"</string>
     <string name="loading" msgid="2526615755685950317">"በመጫን ላይ…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"ውህደት በሂደት ላይ"</string>
diff --git a/apk/res/values-ar/strings.xml b/apk/res/values-ar/strings.xml
index f6c35f4..cfe25e3 100644
--- a/apk/res/values-ar/strings.xml
+++ b/apk/res/values-ar/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"تشتمل هذه البيانات على معلومات، مثل وقت ممارسة النشاط البدني أو نوع التمرين الرياضي أو دورات التمرين أو التكرارات أو الجلسات أو عدد ضربات السباحة."</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"تشتمل هذه البيانات على معلومات، مثل مراحل النوم وجلسات النوم."</string>
     <string name="all_entries_button" msgid="5109091107239135235">"عرض جميع الإدخالات"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"تغيير"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"حذف هذه البيانات"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"الوصول إلى البيانات الصحية"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"مسار التمرين الرياضي"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"كتابة مسار التمرين الرياضي"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"قراءة مسار التمرين الرياضي"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"قراءة جميع مسارات التمارين الرياضية"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"المسافة"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"المسافة"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"قراءة بيانات المسافة"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"معدّل النبض أثناء الراحة"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"قراءة بيانات معدّل النبض أثناء الراحة"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"كتابة بيانات معدّل النبض أثناء الراحة"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"درجة حرارة الجلد"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"درجة حرارة الجلد"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"قراءة بيانات درجة حرارة الجلد"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"كتابة بيانات درجة حرارة الجلد"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"منح تطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الإذن بالقراءة"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"منح التطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" الإذن بالكتابة"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"إلغاء"</string>
@@ -301,7 +307,7 @@
     <string name="manage_your_settings" msgid="7391184508015127137">"إدارة الإعدادات والخصوصية"</string>
     <string name="manage_your_settings_description" msgid="557943168930365334">"يمكنك تغيير أذونات التطبيق وإدارة البيانات في أي وقت."</string>
     <string name="onboarding_go_back_button_text" msgid="5020083846511184625">"الرجوع"</string>
-    <string name="onboarding_get_started_button_text" msgid="2348061971090731336">"البدء"</string>
+    <string name="onboarding_get_started_button_text" msgid="2348061971090731336">"بدء"</string>
     <string name="delete_button_content_description" msgid="9125115327455379618">"حذف البيانات"</string>
     <string name="time_range_title" msgid="6831605283322600165">"اختيار البيانات المُراد حذفها"</string>
     <string name="time_range_next_button" msgid="5849096934896557888">"التالي"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"جارٍ حذف بيانات Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"جارٍ حذف بيانات Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"حذف البيانات"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"حذف إدخالات البيانات"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"حذف إدخال"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"حذف إدخال البيانات <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"حذف الإدخال <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"الإجمالي: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 واط}zero{# واط}two{# واط}few{# واط}many{# واط}other{# واط}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 واط}zero{# واط}two{# واط}few{# واط}many{# واط}other{# واط}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"نقل التطبيق للأسفل"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"نقل التطبيق إلى أعلى القائمة"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"نقل التطبيق إلى أسفل القائمة"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"يُزيل هذا الزر \"<xliff:g id="SELECTED_APP">%s</xliff:g>\" من قائمة أولوية التطبيقات."</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"انقر مرّتين واسحب لإعادة ترتيب التطبيق المحدّد."</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"اللياقة البدنية، الحالة الصحية"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"الأذونات"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect، البيانات الصحية، الفئات الصحية، الوصول إلى البيانات، النشاط، قياسات الجسم، تتبُّع الدورة الشهريّة، التغذية، النوم، المؤشرات الحيوية"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"التطبيقات فقط التي تسمح لها بالوصول إلى مسارات التمارين الرياضية"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"كيف يمكنني إدارة أذونات الوصول؟"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"يمكنك إدارة أذونات وصول التطبيقات إلى مسارات التمارين الرياضية في إعدادات Health Connect."</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"رجوع"</string>
     <string name="loading" msgid="2526615755685950317">"جارٍ التحميل…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"جارٍ تنفيذ عملية الدمج"</string>
diff --git a/apk/res/values-as/strings.xml b/apk/res/values-as/strings.xml
index b0af940..645822c 100644
--- a/apk/res/values-as/strings.xml
+++ b/apk/res/values-as/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"এই ডেটাত সক্ৰিয় হৈ থকাৰ সময়, ব্যায়ামৰ ধৰণ, দৌৰি ঘূৰি অহা পাকৰ সংখ্যা, পুনৰাবৃত্তি, ছেশ্বন অথবা ছুইমিং ষ্ট্ৰোক অন্তৰ্ভুক্ত"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"এই ডেটাত শোৱাৰ স্তৰ আৰু শোৱাৰ ছেশ্বনৰ দৰে তথ্য অন্তৰ্ভুক্ত"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"আটাইবোৰ প্ৰবিষ্টি চাওক"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"সলনি কৰক"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"এই ডেটাখিনি মচক"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"আপোনাৰ স্বাস্থ্য সম্পৰ্কীয় ডেটাৰ এক্সেছ"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ব্যায়াম কৰাৰ পথ"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"ব্যায়াম কৰাৰ পথটো লিখক"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"ব্যায়াম কৰাৰ পদ্ধতি পঢ়ক"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"আপোনাৰ আটাইবোৰ ব্যায়ামৰ পথ পঢ়ক"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"দূৰত্ব"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"দূৰত্ব"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"দূৰত্বৰ ডেটা পঢ়ক"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"বিশ্ৰামৰ সময়ত হৃদস্পন্দনৰ হাৰ"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"বিশ্ৰামৰ সময়ত হৃদস্পন্দনৰ হাৰৰ ডেটা পঢ়ক"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"বিশ্ৰামৰ সময়ত হৃদস্পন্দনৰ হাৰৰ ডেটা লিখক"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"ছালৰ তাপমাত্ৰা"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"ছালৰ তাপমাত্ৰা"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"ছালৰ তাপমাত্ৰা জোখক"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"ছালৰ তাপমাত্ৰা লিখক"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”ক পঢ়িবলৈ দিয়ক"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”ক লিখিবলৈ দিয়ক"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"বাতিল কৰক"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connectৰ ডেটা মচি থকা হৈছে"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connectৰ ডেটা মচি থকা হৈছে"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"ডেটা মচা"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"ডেটা এণ্ট্ৰী মচক"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"প্ৰৱিষ্টি মচক"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ডেটা এণ্ট্ৰী মচক"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> এণ্ট্ৰী মচক"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"মুঠ: <xliff:g id="TOTAL_VALUE">%s</xliff:g> টা"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{১ ৱাট}one{# ৱাট}other{# ৱাট}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{১ ৱাট}one{# ৱাট}other{# ৱাট}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"তললৈ নিয়ক"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"একেবাৰে ওপৰলৈ নিয়ক"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"একেবাৰে তললৈ নিয়ক"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"অগ্ৰাধিকাৰৰ সূচীখনৰ পৰা <xliff:g id="SELECTED_APP">%s</xliff:g> আঁতৰাবলৈ বুটাম"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"ক্ৰম সলনি কৰিবলৈ দুবাৰ টিপক আৰু টানি আনক"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ফিটনেছ, সুস্থতা"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"অনুমতি"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, স্বাস্থ্য সম্পৰ্কীয় ডেটা, স্বাস্থ্যৰ শিতান, ডেটাৰ এক্সেছ, কাৰ্যকলাপ, শৰীৰৰ জোখ-মাখ, ঋতুচক্ৰ ট্ৰেক কৰা, পৰিপুষ্টি, টোপনি, ভাইটেল"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"কেৱল আপুনি আপোনাৰ ব্যায়ামৰ পথসমূহ এক্সেছ কৰিবলৈ অনুমতি দিয়া এপ্"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"মই এক্সেছ কেনেকৈ পৰিচালনা কৰিব পাৰোঁ?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"আপুনি Health Connectৰ ছেটিঙত ব্যায়ামৰ পথসমূহৰ বাবে এপৰ এক্সেছ পৰিচালনা কৰিব পাৰে"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"উভতি যাওক"</string>
     <string name="loading" msgid="2526615755685950317">"ল’ড হৈ আছে…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"একত্ৰিত কৰি থকা হৈছে"</string>
diff --git a/apk/res/values-az/strings.xml b/apk/res/values-az/strings.xml
index a75e9e6..f78c88c 100644
--- a/apk/res/values-az/strings.xml
+++ b/apk/res/values-az/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Bu dataya aktiv vaxt, məşq növü, dövrələr, təkrarlar, seanslar və ya üzgüçülük məşqləri kimi məlumatlar daxildir."</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Bu dataya yuxu mərhələləri və yuxu seansları kimi məlumatlar daxildir"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Bütün daxiletmələrə baxın"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"dəyişin"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Bu datanı silin"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"sağlamlıq datanıza giriş"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"məşq marşrutu"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Məşq marşrutunu yazmaq"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Məşq marşrutunu oxuyun"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Bütün məşq marşrutlarının oxunması"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Məsafə"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"məsafə"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Məsafəni oxumaq"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"istirahət zamanı ürək döyüntüsü"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"İstirahət zamanı ürək döyüntüsünü oxumaq"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"İstirahət zamanı ürək döyüntüsünü yazmaq"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Dəri temperaturu"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"dəri temperaturu"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Dəri temperaturunun oxunması"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Dəri temperaturunun yazılması"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" tətbiqinə oxumaq üçün icazə verin"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" tətbiqinə yazmaq üçün icazə verin"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Ləğv edin"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect datasının silinməsi"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect datasının silinməsi"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Datanın silinməsi"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Data daxiletməsini silin"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Daxiletməni silin"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Data daxiletməsini (<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>) silin"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Daxiletməni (<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>) silin"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Cəmi: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 V}other{# V}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vat}other{# vat}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Aşağı köçürün"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Üstə köçürün"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Alta köçürün"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"<xliff:g id="SELECTED_APP">%s</xliff:g> tətbiqini prioritet siyahısından silmə düyməsi"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"İki dəfə toxunub sürüşdürərək yenidən sıralayın"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitnes, sağlamlıq"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"icazələr"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, sağlamlıq datası, sağlamlıq kateqoriyaları, data girişi, fəaliyyət, bədən ölçüləri, tsikl izləmə, qidalanma, yuxu, sağlamlıq göstəriciləri"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Yalnız idman marşrutuna giriş icazəsi verdiyiniz tətbiqlər"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Girişi necə idarə edə bilərəm?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Health Connect ayarlarında tətbiqin idman marşrutuna girişini idarə edə bilərsiniz"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Geri"</string>
     <string name="loading" msgid="2526615755685950317">"Yüklənir…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"İnteqrasiya edilir"</string>
diff --git a/apk/res/values-b+sr+Latn/strings.xml b/apk/res/values-b+sr+Latn/strings.xml
index 4c2bc0e..e880872 100644
--- a/apk/res/values-b+sr+Latn/strings.xml
+++ b/apk/res/values-b+sr+Latn/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Ovi podaci obuhvataju informacije poput vremena aktivnosti, tipa vežbanja, krugova, ponavljanja, sesija ili zaveslaja"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Ovi podaci obuhvataju informacije poput faza sna i sesija spavanja"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Prikaži sve stavke"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"promeni"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Izbriši ove podatke"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Povezivanje zdravlja"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"pristup podacima o zdravlju"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ruta vežbanja"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Upisivanje rute vežbanja"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Čitanje rute vežbanja"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Čitaj sve rute vežbanja"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Razdaljina"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"razdaljina"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Čitanje podataka o razdaljini"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"puls u mirovanju"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Čitanje podataka o pulsu u mirovanju"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Upisivanje podataka o pulsu u mirovanju"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura kože"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura kože"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Čitaj podatke o temperaturi kože"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Upisuj podatke o temperaturi kože"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Dozvola da <xliff:g id="APP_NAME">%1$s</xliff:g> očitava podatke"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Dozvola da <xliff:g id="APP_NAME">%1$s</xliff:g> upisuje podatke"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Otkaži"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Brišu se podaci Povezivanja zdravlja"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Brišu se podaci Povezivanja zdravlja"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Brisanje podataka"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Izbriši unos podataka"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Izbriši unos"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Izbriši unos podataka <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Izbriši unos <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Ukupno: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}few{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vat}one{# vat}few{# vata}other{# vati}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Pomerite nadole"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Premestite na vrh"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Premestite na dno"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Dugme za uklanjanje aplikacije <xliff:g id="SELECTED_APP">%s</xliff:g> sa liste prioriteta"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Dvaput dodirnite i prevucite za promenu redosleda"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitnes, velnes"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"dozvole"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"povezivanje zdravlja, zdravstveni podaci, zdravstvene kategorije, pristup podacima, aktivnost, telesne mere, praćenje ciklusa, ishrana, spavanje, vitalne funkcije"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Samo aplikacije kojima dozvolite da pristupaju rutama za vežbanje"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Kako mogu da upravljam pristupom?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Možete da upravljate pristupom aplikacija rutama za vežbanje u podešavanjima Povezivanja zdravlja"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Nazad"</string>
     <string name="loading" msgid="2526615755685950317">"Učitava se…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integracija je u toku"</string>
diff --git a/apk/res/values-be/strings.xml b/apk/res/values-be/strings.xml
index 29484a7..2cbb16e 100644
--- a/apk/res/values-be/strings.xml
+++ b/apk/res/values-be/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Гэтыя даныя ўключаюць такую інфармацыю, як час актыўнасці, тып практыкавання, кругі, паўтарэнні, сеансы і грабкі"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Гэтыя даныя ўключаюць такую інфармацыю, як стадыі і фазы сну"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Праглядзець усе запісы"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"змяніць"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Выдаліць гэтыя даныя"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Здароўе і спорт"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"доступ да даных, датычных здароўя"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"маршрут трэніроўкі"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Запісваць маршрут трэніроўкі"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Азнаёміцца з праграмай трэніроўкі"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Чытаць усе маршруты трэніровак"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Адлегласць"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"адлегласць"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Счытваць даныя пра адлегласць"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"пульс у стане спакою"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Счытваць даныя пра пульс у стане спакою"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Запісваць даныя пра пульс у стане спакою"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Тэмпература скуры"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"тэмпература скуры"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Чытанне даных пра тэмпературу скуры"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Запіс даных пра тэмпературу скуры"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Дазвольце праграме “<xliff:g id="APP_NAME">%1$s</xliff:g>” счытваць даныя"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Дазвольце праграме “<xliff:g id="APP_NAME">%1$s</xliff:g>” запісваць даныя"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Скасаваць"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Выдаленне даных з праграмы \"Здароўе і спорт\""</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Выдаленне даных з праграмы \"Здароўе і спорт\""</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Выдаленне даных"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Выдаліць запіс даных"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Выдаліць запіс"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Выдаліць запіс даных \"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>\""</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Выдаліць запіс \"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>\""</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Усяго: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 Вт}one{# Вт}few{# Вт}many{# Вт}other{# Вт}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ват}one{# ват}few{# ваты}many{# ватаў}other{# вата}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Перамясціць уніз"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Перамясціць наверх"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Перамясціць уніз"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Кнопка для выдалення праграмы \"<xliff:g id="SELECTED_APP">%s</xliff:g>\" з прыярытэтных"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Змяніце парадак перацягваннем, націснуўшы двойчы"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"фітнес, здароўе"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"дазволы"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"здароўе і спорт, даныя пра здароўе, катэгорыі здароўя, доступ да даных, актыўнасць, параметры цела, сачэнне за цыклам, харчаванне, сон, паказчыкі арганізма"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Толькі праграмам, у якіх ёсць доступ да вашых маршрутаў трэніровак"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Як кіраваць доступам?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Наладзіць доступ да маршрутаў трэніровак можна ў праграме \"Здароўе і спорт\""</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Назад"</string>
     <string name="loading" msgid="2526615755685950317">"Ідзе загрузка…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Выконваецца інтэграцыя"</string>
diff --git a/apk/res/values-bg/strings.xml b/apk/res/values-bg/strings.xml
index 8ab1b18..b777dcd 100644
--- a/apk/res/values-bg/strings.xml
+++ b/apk/res/values-bg/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Тези данни включват различна информация, като например времето на активност, типа на упражненията, обиколките, повторенията, сесиите или загребванията при плуване"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Тези данни включват различна информация, като например фазите и сесиите, свързани със съня"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Преглед на всички записи"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"промяна"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Изтриване на тези данни"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"достъп до здравните ви данни"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"маршрут за упражненията"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Записване на маршрута за упражненията"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Четене на маршрута за упражненията"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Четене на всички маршрути за упражнения"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Разстояние"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"разстояние"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Четене на разстоянието"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"сърдечен ритъм при покой"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Четене на сърдечния ритъм при покой"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Записване на сърдечния ритъм при покой"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Температура на кожата"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"температура на кожата"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Четене на температурата на кожата"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Записване на температурата на кожата"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Разрешаване на <xliff:g id="APP_NAME">%1$s</xliff:g> да чете"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Разрешаване на <xliff:g id="APP_NAME">%1$s</xliff:g> да записва"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Отказ"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Данните в Health Connect се изтриват"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Данните в Health Connect се изтриват"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Изтриване на данни"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Изтриване на записа с данни"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Изтриване на записа"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Изтриване на записа с данни „<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>“"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Изтриване на записа „<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>“"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Общо: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ват}other{# вата}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Преместване надолу"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Преместване в горната част"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Преместване в долната част"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Бутон за премахване на <xliff:g id="SELECTED_APP">%s</xliff:g> от приоритетния списък"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Докоснете два пъти и плъзнете, за да пренаредите"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"фитнес, благосъстояние"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"разрешения"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, здравни данни, здравни категории, достъп до данни, активност, мерки на тялото, проследяване на цикъла, хранене, сън, жизнени показатели"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Само приложенията, на които сте предоставили достъп до маршрутите си за упражнения"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Как мога да управлявам достъпа?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Можете да управлявате достъпа на приложенията до маршрутите за упражнения от настройките на Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Назад"</string>
     <string name="loading" msgid="2526615755685950317">"Зарежда се…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Интегрирането е в ход"</string>
diff --git a/apk/res/values-bn/strings.xml b/apk/res/values-bn/strings.xml
index 3ad69f2..f83b289 100644
--- a/apk/res/values-bn/strings.xml
+++ b/apk/res/values-bn/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"কতক্ষণ ব্যায়াম করেছেন, ব্যায়ামের ধরন, ল্যাপের সংখ্যা, রিপিট হওয়া, সেশন বা সাঁতারের স্ট্রোকের মতো তথ্য এই ডেটায় অন্তর্ভুক্ত থাকে"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ঘুমের বিভিন্ন পর্যায় ও স্লিপ সেশনের মতো তথ্য এই ডেটায় অন্তর্ভুক্ত থাকে"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"সব এন্ট্রি দেখুন"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"পরিবর্তন করুন"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"এই ডেটা মুছুন"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"আপনার স্বাস্থ্য সংক্রান্ত ডেটা অ্যাক্সেস করুন"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ব্যায়ামের পদ্ধতি"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"ব্যায়ামের পদ্ধতি লিখুন"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"ব্যায়ামের রুটিন দেখা"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"আপনার ব্যায়াম করার সমস্ত উপায় পড়ার অনুমতি দিন"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"দূরত্ব"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"দূরত্ব"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"দূরত্ব সংক্রান্ত ডেটা দেখুন"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"বিশ্রামকালীন হার্ট রেট সংক্রান্ত ডেটা"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"বিশ্রামকালীন হার্ট রেট সংক্রান্ত ডেটা দেখুন"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"বিশ্রামকালীন হার্ট রেট সংক্রান্ত ডেটা এডিট করুন"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"শরীরের তাপমাত্রার ডেটা"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"শরীরের তাপমাত্রার ডেটা"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"শরীরের তাপমাত্রার ডেটা দেখার অনুমতি"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"শরীরের তাপমাত্রার ডেটা এডিট করার অনুমতি"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”-কে দেখার অনুমতি দিন"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”-কে এডিট করার অনুমতি দিন"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"বাতিল করুন"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect-এ থাকা ডেটা মুছে ফেলা"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect-এ থাকা ডেটা মুছে ফেলা"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"ডেটা মুছে ফেলা"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"ডেটা এন্ট্রি মুছুন"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"এন্ট্রি মুছুন"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"ডেটা এন্ট্রি <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> মুছুন"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"এন্ট্রি <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> মুছুন"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"মোট: <xliff:g id="TOTAL_VALUE">%s</xliff:g>টি"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{১ ওয়াট}one{# ওয়াট}other{# ওয়াট}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{১ ওয়াট}one{# ওয়াট}other{# ওয়াট}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"নিচে নামান"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"উপরে সরান"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"নিচে সরিয়ে দিন"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"অগ্রাধিকারের তালিকা থেকে <xliff:g id="SELECTED_APP">%s</xliff:g> সরানোর বোতাম"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"নতুন করে সাজাতে, ডবল ট্যাপ করে টেনে আনুন"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ফিটনেস, সুস্থতা"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"অনুমতি"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, স্বাস্থ্য সংক্রান্ত ডেটা, স্বাস্থ্য বিভাগ, ডেটা অ্যাক্সেস, অ্যাক্টিভিটি, শরীরের পরিমাপ সংক্রান্ত ডেটা, সাইকেল ট্র্যাকিং, নিউট্রিশন, স্লিপ, জরুরি তথ্য"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"শুধুমাত্র যেসব অ্যাপকে আপনি এক্সারসাইজ রুট অ্যাক্সেস করার অনুমতি দিয়েছেন"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"কীভাবে আমি অ্যাক্সেস ম্যানেজ করব?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Health Connect-এর সেটিংসে গিয়ে, এক্সারসাইজ রুটে অ্যাপের অ্যাক্সেস ম্যানেজ করতে পারবেন"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"ফিরে যান"</string>
     <string name="loading" msgid="2526615755685950317">"লোড হচ্ছে…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"ইন্টিগ্রেশনের কাজ চলছে"</string>
diff --git a/apk/res/values-bs/strings.xml b/apk/res/values-bs/strings.xml
index 59a1fb5..bb62906 100644
--- a/apk/res/values-bs/strings.xml
+++ b/apk/res/values-bs/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Podaci sadržavaju informacije kao što su aktivno vrijeme, vrsta vježbanja, krugovi, ponavljanja, sesije ili zamasi u plivanju"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Podaci sadržavaju informacije kao što su faze sna i sesije spavanja"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Prikaži sve unose"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"promjena"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Izbriši ove podatke"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"pristupanje podacima o zdravlju"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ruta za vježbanje"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Zapisivanje rute za vježbanje"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Čitanje rute vježbe"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Čitanje svih ruta vježbanja"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Udaljenost"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"udaljenost"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Čitanje udaljenosti"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"puls u mirovanju"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Čitanje pulsa u mirovanju"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Zapisivanje pulsa u mirovanju"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura kože"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura kože"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Čitanje temperature kože"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Zapisivanje temperature kože"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Dozvoli aplikaciji \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" čitanje"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Dozvoli aplikaciji \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" zapisivanje"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Otkaži"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Brisanje podataka Health Connecta"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Brisanje podataka Health Connecta"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Brisanje podataka"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Izbriši unos podataka"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Izbriši unos"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Brisanje unosa podataka <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Brisanje unosa <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Ukupno: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}few{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vat}one{# vat}few{# vata}other{# vati}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Pomjeranje nadolje"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Pomjeranje na vrh"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Pomjeranje na dno"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Dugme za uklanjanje aplikacije <xliff:g id="SELECTED_APP">%s</xliff:g> s liste prioriteta"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Promjena redoslij. dvostrukim dodirom i prevlačenjem"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitnes, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"odobrenja"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, zdravstveni podaci, zdravstvene kategorije, pristup podacima, aktivnost, tjelesne mjere, praćenje ciklusa, prehrana, spavanje, vitalne funkcije"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Samo aplikacije kojima dozvolite pristup rutama za vježbanje"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Kako mogu upravljati pristupom?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Možete upravljati pristupom aplikacija rutama za vježbanje u postavkama Health Connecta"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Nazad"</string>
     <string name="loading" msgid="2526615755685950317">"Učitavanje…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integracija je u toku"</string>
diff --git a/apk/res/values-ca/strings.xml b/apk/res/values-ca/strings.xml
index c6628fb..d130068 100644
--- a/apk/res/values-ca/strings.xml
+++ b/apk/res/values-ca/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Aquestes dades inclouen informació com ara el temps d\'activitat, el tipus d\'exercici, les voltes, les repeticions, les sessions o les braçades"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Aquestes dades inclouen informació com ara les fases del son i les sessions de son"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Mostra totes les entrades"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"canvia"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Suprimeix aquestes dades"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Salut connectada"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"accedir a les teves dades de salut"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ruta d\'exercici"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Escriu la ruta d\'exercici"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Llegeix la ruta d\'exercici"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Llegeix totes les rutes d\'exercici"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distància"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distància"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Llegir la distància"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"freqüència cardíaca en repòs"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Llegir la freqüència cardíaca en repòs"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Escriure la freqüència cardíaca en repòs"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura de la pell"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura de la pell"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Llegir la temperatura de la pell"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Escriure la temperatura de la pell"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Permet que <xliff:g id="APP_NAME">%1$s</xliff:g> llegeixi"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Permet que <xliff:g id="APP_NAME">%1$s</xliff:g> escrigui"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Cancel·la"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"S\'estan suprimint les dades de Salut connectada"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"S\'estan suprimint les dades de Salut connectada"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Supressió de dades"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Suprimeix l\'entrada de dades"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Suprimeix l\'entrada"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Suprimeix l\'entrada de dades <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Suprimeix l\'entrada <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watts}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Mou cap avall"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Mou al principi"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Mou al final"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Botó per suprimir <xliff:g id="SELECTED_APP">%s</xliff:g> de la llista prioritària"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Fes doble toc i arrossega per reordenar"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitnes, benestar"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"permisos"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"salut connectada, dades de salut, categories de salut, accés a les dades, activitat, mesures corporals, seguiment del cicle, nutrició, son, constants vitals"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Només les aplicacions a què donis accés a les teves rutes d\'exercici"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Com puc gestionar l\'accés?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Pots gestionar l\'accés de les aplicacions a les rutes d\'exercici a la configuració de Salut connectada"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Enrere"</string>
     <string name="loading" msgid="2526615755685950317">"S\'està carregant…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integració en curs"</string>
diff --git a/apk/res/values-cs/strings.xml b/apk/res/values-cs/strings.xml
index 67d0b93..fe824d2 100644
--- a/apk/res/values-cs/strings.xml
+++ b/apk/res/values-cs/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Tato data zahrnují informace jako čas aktivity, druh cvičení, počet kol, počet sérií nebo počet plaveckých temp"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Tato data zahrnují informace jako fáze spánku a období spánku"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Zobrazit všechny záznamy"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"změnit"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Smazat tato data"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"přístup ke zdravotním údajům"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"tréninková trasa"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Zapsat tréninkovou trasu"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Čtení průběhu cvičení"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Číst všechny tréninkové trasy"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Vzdálenost"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"vzdálenost"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Číst vzdálenost"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"srdeční tep v klidu"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Číst srdeční tep v klidu"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Zapisovat srdeční tep v klidu"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Teplota kůže"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"teplota kůže"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Čtení teploty kůže"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Zápis teploty kůže"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Povolit aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g> čtení"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Povolit aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g> zápis"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Zrušit"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Mazání dat Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Mazání dat Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Smazání dat"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Smazat záznam"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Smazat záznam"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Smazat záznam <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Smazat záznam <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Celkem: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}few{# W}many{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}few{# watty}many{# wattu}other{# wattů}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Přesunout dolů"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Přesunout na začátek"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Přesunout na konec"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Tlačítko k odstranění aplikace <xliff:g id="SELECTED_APP">%s</xliff:g> z priority"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Dvojitým klepnutím a přetažením změníte pořadí"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"oprávnění"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, zdravotní údaje, zdravotní kategorie, přístup k datům, aktivita, tělesné míry, sledování cyklu, výživa, spánek, vitals"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Pouze aplikace, kterým povolíte přístup ke svým tréninkovým trasám"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Jak mohu spravovat přístup?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Přístup aplikace k tréninkovým trasám můžete spravovat v nastavení Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Zpět"</string>
     <string name="loading" msgid="2526615755685950317">"Načítání…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Probíhá integrace"</string>
diff --git a/apk/res/values-da/strings.xml b/apk/res/values-da/strings.xml
index cd1554a..9240983 100644
--- a/apk/res/values-da/strings.xml
+++ b/apk/res/values-da/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Disse data omfatter oplysninger som f.eks. aktiv tid og træningstype samt antallet af omgange, gentagelser, træningspas og svømmetag"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Disse data omfatter oplysninger som f.eks. søvnstadier og soveperioder"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Se alle poster"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"skift"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Slet disse data"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"få adgang til dine sundhedsdata"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"træningsrute"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Skriv træningsrute"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Læs træningsrute"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Giv tilladelse til at læse alle træningsruter"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Afstand"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"afstand"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Læs afstand"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"hvilepuls"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Læs hvilepuls"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Skriv hvilepuls"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Hudtemperatur"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"hudtemperatur"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Læs hudtemperatur"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Skriv hudtemperatur"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Giv \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" tilladelse til at læse"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Giv \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" tilladelse til at skrive"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Annuller"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Sletter Health Connect-data"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Sletter Health Connect-data"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Sletning af data"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Slet datapost"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Slet post"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Slet dataposten <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Slet posten <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"I alt: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}one{# watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Flyt ned"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Flyt til toppen"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Flyt til bunden"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Knap til at fjerne <xliff:g id="SELECTED_APP">%s</xliff:g> fra prioritetslisten"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Tryk to gange og træk for at omorganisere"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"træning, velvære"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"tilladelser"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, sundhedsdata, sundhedskategorier, dataadgang, aktivitet, kropsmål, tracking af cyklus, ernæring, søvn, vitale værdier"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Kun de apps, som du giver lov til at tilgå dine træningsruter"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Hvordan kan jeg styre adgangen?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Du kan administrere adgangen af dine apps til træningsruter i indstillingerne for Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Tilbage"</string>
     <string name="loading" msgid="2526615755685950317">"Indlæser…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integrationen er i gang"</string>
diff --git a/apk/res/values-de/strings.xml b/apk/res/values-de/strings.xml
index 1441548..adf820d 100644
--- a/apk/res/values-de/strings.xml
+++ b/apk/res/values-de/strings.xml
@@ -45,8 +45,7 @@
     <string name="write_data_access_label" msgid="7955988316773000250">"Schreiben: %s"</string>
     <string name="data_type_separator" msgid="1299848322898210658">", "</string>
     <string name="manage_permissions" msgid="8394221950712608160">"Berechtigungen verwalten"</string>
-    <!-- no translation found for recent_access_time_content_descritption (1709675393952226273) -->
-    <skip />
+    <string name="recent_access_time_content_descritption" msgid="1709675393952226273">"Zeit: %s"</string>
     <string name="activity_category_uppercase" msgid="136628843341377088">"Aktivität"</string>
     <string name="activity_category_lowercase" msgid="3007220578865400601">"Aktivität"</string>
     <string name="body_measurements_category_uppercase" msgid="422923782603313038">"Körperwerte"</string>
@@ -76,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Zu diesen Daten gehören beispielsweise Aktivitätsdauer, Sportart, Runden, Wiederholungen, Trainingseinheiten und Schwimmzüge"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Zu diesen Daten gehören beispielsweise Schlafphasen und Schlafperioden"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Alle Einträge ansehen"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"ändern"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Diese Daten löschen"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"Auf meine Gesundheitsdaten zugreifen"</string>
@@ -96,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"Trainingsroute"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Trainingsroute schreiben"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Trainingsroute ansehen"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Alle Trainingsrouten einsehen"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Strecke"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"Strecke"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Strecke lesen"</string>
@@ -241,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"Ruheherzfrequenz"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Ruheherzfrequenz lesen"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Ruheherzfrequenz schreiben"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Hauttemperatur"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"Hauttemperatur"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Hauttemperatur lesen"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Hauttemperatur schreiben"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ Lesezugriff gewähren"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ Schreibzugriff gewähren"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Abbrechen"</string>
@@ -348,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect-Daten werden gelöscht"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect-Daten werden gelöscht"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Datenlöschung"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Dateneintrag löschen"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Eintrag löschen"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Dateneintrag „<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>“ löschen"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Eintrag „<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>“ löschen"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Gesamt: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 Watt}other{# Watt}}"</string>
@@ -711,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Nach unten verschieben"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"An den Anfang verschieben"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Ans Ende verschieben"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Taste zum Entfernen von <xliff:g id="SELECTED_APP">%s</xliff:g> aus der Prioritätenliste"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Doppeltippen und ziehen, um Reihenfolge zu ändern"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"berechtigungen"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, gesundheitsdaten, gesundheitskategorien, datenzugriff, aktivitäten, körperwerte, zyklustracking, ernährung, schlaf, vitalparameter"</string>
@@ -727,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Nur Apps, denen du erlaubst, auf deine Trainingsrouten zuzugreifen"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Wie kann ich den Zugriff verwalten?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Du kannst den App-Zugriff auf Trainingsrouten in den Einstellungen von Health Connect verwalten"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Zurück"</string>
     <string name="loading" msgid="2526615755685950317">"Wird geladen…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integration läuft"</string>
diff --git a/apk/res/values-el/strings.xml b/apk/res/values-el/strings.xml
index 7d7b5e4..c43b06a 100644
--- a/apk/res/values-el/strings.xml
+++ b/apk/res/values-el/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Αυτά τα δεδομένα περιλαμβάνουν πληροφορίες όπως είναι ο χρόνος σωματικής δραστηριότητας, ο τύπος της άσκησης, οι γύροι, οι επαναλήψεις ή οι απλωτές κατά την κολύμβηση"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Αυτά τα δεδομένα περιλαμβάνουν πληροφορίες όπως είναι τα στάδια του ύπνου και οι περίοδοι ύπνου"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Εμφάνιση όλων των καταχωρίσεων"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"αλλαγή"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Διαγραφή αυτών των δεδομένων"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"πρόσβαση σε δεδομένα υγείας"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"διαδρομή άσκησης"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Εγγραφή διαδρομής άσκησης"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Ανάγνωση διαδρομής άσκησης"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Ανάγνωση όλων των διαδρομών άσκησης"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Απόσταση"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"απόσταση"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Ανάγνωση δεδομένων απόστασης"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"καρδιακός ρυθμός χαλάρωσης"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Ανάγνωση δεδομένων καρδιακού ρυθμού χαλάρωσης"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Εγγραφή δεδομένων καρδιακού ρυθμού χαλάρωσης"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Θερμοκρασία δέρματος"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"θερμοκρασία δέρματος"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Ανάγνωση θερμοκρασίας δέρματος"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Εγγραφή θερμοκρασίας δέρματος"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Παροχή στην εφαρμογή “<xliff:g id="APP_NAME">%1$s</xliff:g>” του δικαιώματος ανάγνωσης"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Να επιτρέπεται στην εφαρμογή “<xliff:g id="APP_NAME">%1$s</xliff:g>” να γράφει"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Ακύρωση"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Γίνεται διαγραφή των δεδομένων Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Γίνεται διαγραφή των δεδομένων Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Διαγραφή δεδομένων"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Διαγραφή καταχώρισης δεδομένων"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Διαγραφή καταχώρισης"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Διαγραφή καταχώρισης δεδομένων <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Διαγραφή καταχώρισης <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Σύνολο: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Μετακίνηση προς τα κάτω"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Μετακίνηση στην κορυφή"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Μετακίνηση στο τέλος"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Κουμπί κατάργησης <xliff:g id="SELECTED_APP">%s</xliff:g> από τη λίστα προτεραιοτήτων"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Πατήστε δύο φορές και σύρετε για αλλαγή σειράς"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"φυσική κατάσταση, ευεξία"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"άδειες"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, δεδομένα υγείας, κατηγορίες υγείας, πρόσβαση δεδομένων, δραστηριότητα, μετρήσεις σώματος, παρακολούθηση κύκλου, διατροφή, ύπνος, ζωτικές λειτουργίες"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Μόνο οι εφαρμογές στις οποίες επιτρέπετε να έχουν πρόσβαση στις διαδρομές άσκησης"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Πώς μπορώ να διαχειριστώ την πρόσβαση;"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Μπορείτε να διαχειριστείτε την πρόσβαση εφαρμογών στις διαδρομές άσκησης μέσω των ρυθμίσεων του Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Πίσω"</string>
     <string name="loading" msgid="2526615755685950317">"Φόρτωση…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Η ενσωμάτωση είναι σε εξέλιξη"</string>
diff --git a/apk/res/values-en-rAU/strings.xml b/apk/res/values-en-rAU/strings.xml
index d91a7bd..f5a2cb2 100644
--- a/apk/res/values-en-rAU/strings.xml
+++ b/apk/res/values-en-rAU/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"This data includes information like active time, exercise type, laps, repetitions, sessions or swimming strokes"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"This data includes information like sleep stages and sleep sessions"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"See all entries"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"change"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Delete this data"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"access your health data"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"exercise route"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Write exercise route"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Read exercise route"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Read all exercise routes"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distance"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distance"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Read distance"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"resting heart rate"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Read resting heart rate"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Write resting heart rate"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Skin temperature"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"skin temperature"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Read skin temperature"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Write skin temperature"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Allow \'<xliff:g id="APP_NAME">%1$s</xliff:g>\' to read"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Allow \'<xliff:g id="APP_NAME">%1$s</xliff:g>\' to write"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Cancel"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Deleting Health Connect data"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Deleting Health Connect data"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Data deletion"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Delete data entry"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Delete entry"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Delete data entry <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Delete entry <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watts}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Move down"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Move to top"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Move to bottom"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Button to remove <xliff:g id="SELECTED_APP">%s</xliff:g> from the priority list"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Double-tap and drag to reorder"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"permissions"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, health data, health categories, data access, activity, body measurements, cycle tracking, nutrition, sleep, vitals"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Only apps that you allow to access your exercise routes"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"How can I manage access?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"You can manage app access to exercise routes in Health Connect settings"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Back"</string>
     <string name="loading" msgid="2526615755685950317">"Loading…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integration in progress"</string>
diff --git a/apk/res/values-en-rCA/strings.xml b/apk/res/values-en-rCA/strings.xml
index 43bb21e..b97886d 100644
--- a/apk/res/values-en-rCA/strings.xml
+++ b/apk/res/values-en-rCA/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"This data includes information like active time, exercise type, laps, repetitions, sessions, or swimming strokes"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"This data includes information like sleep stages and sleep sessions"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"See all entries"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"change"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Delete this data"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"access your health data"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"exercise route"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Write exercise route"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Read exercise route"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Read all exercise routes"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distance"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distance"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Read distance"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"resting heart rate"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Read resting heart rate"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Write resting heart rate"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Skin temperature"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"skin temperature"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Read skin temperature"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Write skin temperature"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Allow “<xliff:g id="APP_NAME">%1$s</xliff:g>” to read"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Allow “<xliff:g id="APP_NAME">%1$s</xliff:g>” to write"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Cancel"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Deleting Health Connect data"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Deleting Health Connect data"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Data deletion"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Delete data entry"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Delete entry"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Delete data entry <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Delete entry <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watts}}"</string>
@@ -710,6 +716,9 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Move down"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Move to top"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Move to bottom"</string>
+    <string name="reorder_button_content_description" msgid="2685032520710743533">"Button to drag and reorder <xliff:g id="SELECTED_APP">%s</xliff:g> in the priority list"</string>
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Button to remove <xliff:g id="SELECTED_APP">%s</xliff:g> from the priority list"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Double tap and drag to reorder"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"permissions"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, health data, health categories, data access, activity, body measurements, cycle tracking, nutrition, sleep, vitals"</string>
@@ -726,6 +735,9 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Only apps you allow to access your exercise routes"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"How can I manage access?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"You can manage app access to exercise routes in Health Connect settings"</string>
+    <string name="request_route_allow" msgid="4427372851821847274">"Allow this route"</string>
+    <string name="request_route_allow_all" msgid="314830698958736916">"Allow all routes"</string>
+    <string name="request_route_dont_allow" msgid="1186236234664957228">"Don\'t allow"</string>
     <string name="back_button" msgid="780519527385993407">"Back"</string>
     <string name="loading" msgid="2526615755685950317">"Loading…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integration in progress"</string>
diff --git a/apk/res/values-en-rGB/strings.xml b/apk/res/values-en-rGB/strings.xml
index d91a7bd..f5a2cb2 100644
--- a/apk/res/values-en-rGB/strings.xml
+++ b/apk/res/values-en-rGB/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"This data includes information like active time, exercise type, laps, repetitions, sessions or swimming strokes"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"This data includes information like sleep stages and sleep sessions"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"See all entries"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"change"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Delete this data"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"access your health data"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"exercise route"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Write exercise route"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Read exercise route"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Read all exercise routes"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distance"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distance"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Read distance"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"resting heart rate"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Read resting heart rate"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Write resting heart rate"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Skin temperature"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"skin temperature"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Read skin temperature"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Write skin temperature"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Allow \'<xliff:g id="APP_NAME">%1$s</xliff:g>\' to read"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Allow \'<xliff:g id="APP_NAME">%1$s</xliff:g>\' to write"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Cancel"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Deleting Health Connect data"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Deleting Health Connect data"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Data deletion"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Delete data entry"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Delete entry"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Delete data entry <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Delete entry <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watts}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Move down"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Move to top"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Move to bottom"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Button to remove <xliff:g id="SELECTED_APP">%s</xliff:g> from the priority list"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Double-tap and drag to reorder"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"permissions"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, health data, health categories, data access, activity, body measurements, cycle tracking, nutrition, sleep, vitals"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Only apps that you allow to access your exercise routes"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"How can I manage access?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"You can manage app access to exercise routes in Health Connect settings"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Back"</string>
     <string name="loading" msgid="2526615755685950317">"Loading…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integration in progress"</string>
diff --git a/apk/res/values-en-rIN/strings.xml b/apk/res/values-en-rIN/strings.xml
index d91a7bd..f5a2cb2 100644
--- a/apk/res/values-en-rIN/strings.xml
+++ b/apk/res/values-en-rIN/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"This data includes information like active time, exercise type, laps, repetitions, sessions or swimming strokes"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"This data includes information like sleep stages and sleep sessions"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"See all entries"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"change"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Delete this data"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"access your health data"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"exercise route"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Write exercise route"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Read exercise route"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Read all exercise routes"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distance"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distance"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Read distance"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"resting heart rate"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Read resting heart rate"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Write resting heart rate"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Skin temperature"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"skin temperature"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Read skin temperature"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Write skin temperature"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Allow \'<xliff:g id="APP_NAME">%1$s</xliff:g>\' to read"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Allow \'<xliff:g id="APP_NAME">%1$s</xliff:g>\' to write"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Cancel"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Deleting Health Connect data"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Deleting Health Connect data"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Data deletion"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Delete data entry"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Delete entry"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Delete data entry <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Delete entry <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watts}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Move down"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Move to top"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Move to bottom"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Button to remove <xliff:g id="SELECTED_APP">%s</xliff:g> from the priority list"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Double-tap and drag to reorder"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"permissions"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, health data, health categories, data access, activity, body measurements, cycle tracking, nutrition, sleep, vitals"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Only apps that you allow to access your exercise routes"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"How can I manage access?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"You can manage app access to exercise routes in Health Connect settings"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Back"</string>
     <string name="loading" msgid="2526615755685950317">"Loading…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integration in progress"</string>
diff --git a/apk/res/values-en-rXC/strings.xml b/apk/res/values-en-rXC/strings.xml
index c98784f..ee7ae28 100644
--- a/apk/res/values-en-rXC/strings.xml
+++ b/apk/res/values-en-rXC/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎This data includes information like active time, exercise type, laps, repetitions, sessions, or swimming strokes‎‏‎‎‏‎"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‏‏‎‎‎‎‎‏‏‏‏‏‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‎‏‏‎‏‏‎‎‎‎‎‎‏‎‎‎‏‎This data includes information like sleep stages and sleep sessions‎‏‎‎‏‎"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‎‎‎‏‎‎‎‎‎‎‎‎‎‏‏‎See all entries‎‏‎‎‏‎"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‏‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‎‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎change‎‏‎‎‏‎"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‏‎‎‏‏‏‏‏‎‎‎‎‎‏‏‎‏‎‏‎Delete this data‎‏‎‎‏‎"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‎‏‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‎‎Health Connect‎‏‎‎‏‎"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‎‏‏‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‎‏‎‎‏‎access your health data‎‏‎‎‏‎"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‏‎‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‎‏‏‎‏‎‎‎‏‏‎‏‎‎‎exercise route‎‏‎‎‏‎"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‎‏‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‎‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‎‎‏‏‎Write exercise route‎‏‎‎‏‎"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎Read exercise route‎‏‎‎‏‎"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎‏‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‎Read all exercise routes‎‏‎‎‏‎"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‏‏‎‏‏‎‎Distance‎‏‎‎‏‎"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‎‏‎‎‎‎‎‎‎‏‏‎distance‎‏‎‎‏‎"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‏‎‎‎‎‏‎‎‎‎‏‎‎‏‏‏‏‎‎‎‎‏‎‎‎‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎Read distance‎‏‎‎‏‎"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‎resting heart rate‎‏‎‎‏‎"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‎‎‎‏‎‏‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎Read resting heart rate‎‏‎‎‏‎"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‎‎‎‏‏‏‎‏‎‏‎‏‎‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‏‏‎Write resting heart rate‎‏‎‎‏‎"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‏‏‎‎‎‏‏‏‏‎‏‎‏‎‎‎Skin temperature‎‏‎‎‏‎"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‏‎‏‎skin temperature‎‏‎‎‏‎"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‎‎‏‏‎‎‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‏‏‎‎‏‏‏‎‎‏‏‏‎‏‎‏‎Read skin temperature‎‏‎‎‏‎"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎Write skin temperature‎‏‎‎‏‎"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‎‎‏‎‏‏‏‎‏‏‏‏‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‏‎‎‏‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‎‏‏‎‎‎‎Allow “‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎” to read‎‏‎‎‏‎"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‎‎‏‏‎‎‎‏‎‎‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‎‏‏‏‏‎‏‏‏‏‎Allow “‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎” to write‎‏‎‎‏‎"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‎‏‏‏‎‎‏‏‎‎‏‏‎‎‎‏‏‏‎‏‎‎‎‏‏‎‎‎‏‏‎‎‎‎‏‎‎‎‏‎Cancel‎‏‎‎‏‎"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‏‎‏‎‏‎‏‏‎‏‎‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‎‎‏‏‎‏‏‏‎‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‎‏‏‎Deleting Health Connect data‎‏‎‎‏‎"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‎‎‎‏‏‎‏‏‏‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‏‏‏‎‎Deleting Health Connect data‎‏‎‎‏‎"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‏‏‏‏‎Data deletion‎‏‎‎‏‎"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‎‎‎‎‎‏‎‎‎‎‏‎‏‏‏‎‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‏‎‎‎‎‏‎‎‎‏‏‏‏‎‎‎‎‎‏‎‏‎‎Delete data entry‎‏‎‎‏‎"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‎‏‏‎‏‏‎‎Delete entry‎‏‎‎‏‎"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‎‎‎‏‎‎‎‏‎‏‏‎‎‎‏‏‏‎Delete data entry ‎‏‎‎‏‏‎<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‏‎‎‎‎‏‎‏‎‏‎‏‎‎‎‏‎‎Delete entry ‎‏‎‎‏‏‎<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‏‏‎‎‎‎‎‎‎Total: ‎‏‎‎‏‏‎<xliff:g id="TOTAL_VALUE">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‏‎‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎1 W‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‎‎‎‏‏‏‎‏‎‎‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎# W‎‏‎‎‏‎}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎1 watt‎‏‎‎‏‎}other{‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‏‏‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎# watts‎‏‎‎‏‎}}"</string>
@@ -710,6 +716,9 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‎‎Move down‎‏‎‎‏‎"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‎‏‎‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‏‏‎‎‎‏‏‎‏‏‏‏‎‏‏‏‏‏‏‎‎‎Move to top‎‏‎‎‏‎"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‎‎‎‏‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‏‎‏‏‎‎‎‎‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‎‎Move to bottom‎‏‎‎‏‎"</string>
+    <string name="reorder_button_content_description" msgid="2685032520710743533">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‎‏‎‏‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‎‏‏‎‏‎Button to drag and reorder ‎‏‎‎‏‏‎<xliff:g id="SELECTED_APP">%s</xliff:g>‎‏‎‎‏‏‏‎ in the priority list‎‏‎‎‏‎"</string>
+    <string name="remove_button_content_description" msgid="6170490900032612048">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‎‎‏‏‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‎‎‏‎‏‏‎‎‏‏‎‏‏‎‏‎‎‎‎‎Button to remove ‎‏‎‎‏‏‎<xliff:g id="SELECTED_APP">%s</xliff:g>‎‏‎‎‏‏‏‎ from the priority list‎‏‎‎‏‎"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‎‎‎‎‏‎‎‎‏‏‎‎‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‎‎‏‏‎‏‏‏‎‎‏‎‏‏‎‏‏‏‏‎‏‎‏‏‎‎Double tap and drag to reorder‎‏‎‎‏‎"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‎‎‎‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‏‎‎‏‏‎‏‎‎‏‏‎‏‏‎‏‏‏‏‏‏‎fitness, wellness‎‏‎‎‏‎"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‏‏‎‎‏‏‏‏‎‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‎‏‎‎‏‎‎‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‎‏‎permissions‎‏‎‎‏‎"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‎‎‏‎‎‏‏‎‎‏‎‏‏‎‎‎‎‏‎‏‏‏‎‏‎‏‏‎‎‎‏‏‏‎‏‎‏‏‎‏‏‎health connect, health data, health categories, data access, activity, body measurements, cycle tracking, nutrition, sleep, vitals‎‏‎‎‏‎"</string>
@@ -726,6 +735,9 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‎‎‎‏‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‏‎‎Only apps you allow to access your exercise routes‎‏‎‎‏‎"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎‏‎‏‎‎‎‎‎‎‏‎‎‏‎‏‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‏‎‎‎How can I manage access?‎‏‎‎‏‎"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‎‎‏‎‏‎‎‏‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‎‎‎‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‎‎‏‏‎‏‏‏‎You can manage app access to exercise routes in Health Connect settings‎‏‎‎‏‎"</string>
+    <string name="request_route_allow" msgid="4427372851821847274">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎‎‎‎‎‎‏‎‎‏‏‎‏‏‎‎‏‎‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‎‏‎‏‏‏‎‏‎‏‎‎Allow this route‎‏‎‎‏‎"</string>
+    <string name="request_route_allow_all" msgid="314830698958736916">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‎‎‎‎‎‏‏‎‏‏‎‏‎‎‏‎‎‎‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‏‏‏‎‎‎‎‏‎‏‎‎‎Allow all routes‎‏‎‎‏‎"</string>
+    <string name="request_route_dont_allow" msgid="1186236234664957228">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‏‏‏‎‏‏‎‎‏‎‏‏‎‏‏‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‏‏‎‎‎Don\'t allow‎‏‎‎‏‎"</string>
     <string name="back_button" msgid="780519527385993407">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‎‏‎‎‎‏‎‎‎‎‏‎‏‏‏‏‏‏‎Back‎‏‎‎‏‎"</string>
     <string name="loading" msgid="2526615755685950317">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‏‎‏‎‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‎‏‏‎‏‎Loading…‎‏‎‎‏‎"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‏‎‎‏‎‎‎‏‏‎‎‏‎‎‎‏‎‏‎‎‏‏‎‎‏‎‎Integration in progress‎‏‎‎‏‎"</string>
diff --git a/apk/res/values-es-rUS/strings.xml b/apk/res/values-es-rUS/strings.xml
index 3c67a90..b652b3c 100644
--- a/apk/res/values-es-rUS/strings.xml
+++ b/apk/res/values-es-rUS/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Estos datos incluyen información como el tiempo de actividad, el tipo de ejercicio, las vueltas, las repeticiones, las sesiones y las brazadas"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Estos datos incluyen información como las fases y las sesiones de sueño"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Ver todas las entradas"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"cambiar"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Borrar estos datos"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"Acceder a tus datos de salud"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ruta de ejercicio"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Grabar ruta de ejercicio"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Leer la ruta de ejercicio"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Leer todas las rutas de ejercicio"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distancia"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distancia"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Medir distancia"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"frecuencia cardíaca en reposo"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Medir frecuencia cardíaca en reposo"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Registrar frecuencia cardíaca en reposo"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura cutánea"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura cutánea"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Lee la temperatura cutánea"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Escribe la temperatura cutánea"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Permite que \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" tenga permiso de lectura"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Permitir que \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" tenga acceso de escritura"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Cancelar"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Borrando datos de Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Borrando datos de Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Eliminación de datos"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Borrar todos los registros"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Borrar entrada"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Borrar entrada de datos <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Borrar entrada <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vatio}other{# vatios}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Mover hacia abajo"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Mover al principio"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Mover al final"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Botón para quitar <xliff:g id="SELECTED_APP">%s</xliff:g> de la lista de prioridades"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Presiona dos veces y arrastra para reorganizar"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"entrenamiento, bienestar"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"permisos"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, datos de salud, categorías de salud, acceso a los datos, actividad, medidas corporales, seguimiento de ciclos, nutrición, sueño, datos vitales"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Solo las apps a las que les permitas acceder a tus rutas de ejercicio"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"¿Cómo puedo administrar el acceso?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Puedes administrar el acceso de la app a las rutas de ejercicio en la configuración de Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Atrás"</string>
     <string name="loading" msgid="2526615755685950317">"Cargando…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integración en curso"</string>
diff --git a/apk/res/values-es/strings.xml b/apk/res/values-es/strings.xml
index f079683..ba7205f 100644
--- a/apk/res/values-es/strings.xml
+++ b/apk/res/values-es/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Estos datos incluyen información como el tiempo de actividad, el tipo de ejercicio, los largos, las repeticiones, las sesiones o las brazadas"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Estos datos incluyen información como las fases y las sesiones del sueño"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Ver todas las entradas"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"cambiar"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Eliminar estos datos"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Salud conectada"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"acceder a tus datos de salud"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ruta de ejercicio"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Escribir ruta de ejercicio"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Leer ruta de ejercicio"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Leer todas las rutas de ejercicio"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distancia"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distancia"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Leer distancia"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"frecuencia cardiaca en reposo"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Leer frecuencia cardiaca en reposo"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Escribir frecuencia cardiaca en reposo"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura cutánea"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura cutánea"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Leer la temperatura cutánea"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Escribir la temperatura cutánea"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Permitir que <xliff:g id="APP_NAME">%1$s</xliff:g> lea"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Permitir que <xliff:g id="APP_NAME">%1$s</xliff:g> escriba"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Cancelar"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Eliminando datos de Salud conectada"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Eliminando datos de Salud conectada"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Eliminación de datos"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Eliminar entrada de datos"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Eliminar entrada"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Eliminar entrada de datos <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Eliminar entrada <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vatio}other{# vatios}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Mover hacia abajo"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Mover al principio"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Mover al final"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Botón para eliminar <xliff:g id="SELECTED_APP">%s</xliff:g> de la lista prioritaria"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Da dos toques y arrastra para cambiar el orden"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"actividad física, bienestar"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"permisos"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"salud conectada, datos de salud, categorías de salud, acceso a datos, actividad, medidas corporales, seguimiento del ciclo, nutrición, sueño, constantes vitales"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Solo las aplicaciones a las que les permitas acceder a tus rutas de ejercicio"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"¿Cómo puedo gestionar el acceso?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Puedes gestionar el acceso de las aplicaciones a las rutas de ejercicio en los ajustes de Salud conectada"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Atrás"</string>
     <string name="loading" msgid="2526615755685950317">"Cargando…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integración en curso"</string>
diff --git a/apk/res/values-et/strings.xml b/apk/res/values-et/strings.xml
index 85654ad..aba96f7 100644
--- a/apk/res/values-et/strings.xml
+++ b/apk/res/values-et/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Need andmed hõlmavad teavet, nagu aktiveerimisaeg, treeningu tüüp, ringid, kordused, seansid või ujumise tõmbed"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Need andmed hõlmavad teavet, nagu unefaasid ja uneseansid"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Kuva kõik kanded"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"muutmine"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Kustuta need andmed"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"juurdepääs teie terviseandmetele"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"treeningu marsruut"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Treeningu marsruudi kirjutamine"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Treeningu marsruudi lugemine"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Kõigi treeningu marsruutide lugemine"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Vahemaa"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"vahemaa"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Vahemaa lugemine"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"pulss puhkamisel"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Puhkamisaegse pulsi lugemine"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Puhkamisaegse pulsi kirjutamine"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Naha temperatuur"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"naha temperatuur"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Saate lugeda naha temperatuuri"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Saate kirjutada välja naha temperatuuri"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Luba rakendusel „<xliff:g id="APP_NAME">%1$s</xliff:g>“ lugeda"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Luba rakendusel „<xliff:g id="APP_NAME">%1$s</xliff:g>“ kirjutada"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Tühista"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connecti andmete kustutamine"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connecti andmete kustutamine"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Andmete kustutamine"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Kustutage andmesisestus"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Kustuta sisestus"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Andmekirje <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> kustutamine"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Kirje <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> kustutamine"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Kokku: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vatt}other{# vatti}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Teisalda alla"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Teisalda esimeseks"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Teisalda viimaseks"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Nupp rakenduse <xliff:g id="SELECTED_APP">%s</xliff:g> eemaldamiseks prioriteediloendist"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Topeltpuudutage ja lohistage järjestuse muutmiseks"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"treening, heaolu"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"load"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, terviseandmed, terviseandmete kategooriad, juurdepääs andmetele, tegevused, keha mõõtmisandmed, tsükli jälgimine, toitumine, uni, tervisenäitajad"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Ainult need rakendused, millele annate loa juurdepääsuks teie treeningumarsruutidele."</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Kuidas saan juurdepääsu hallata?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Rakenduste juurdepääsu treeningumarsruutidele saate hallata Health Connecti seadete jaotises."</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Tagasi"</string>
     <string name="loading" msgid="2526615755685950317">"Laadimine …"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integratsioon on pooleli"</string>
diff --git a/apk/res/values-eu/strings.xml b/apk/res/values-eu/strings.xml
index 60d65c1..d9b5907 100644
--- a/apk/res/values-eu/strings.xml
+++ b/apk/res/values-eu/strings.xml
@@ -45,7 +45,7 @@
     <string name="write_data_access_label" msgid="7955988316773000250">"Idatzi: %s"</string>
     <string name="data_type_separator" msgid="1299848322898210658">", "</string>
     <string name="manage_permissions" msgid="8394221950712608160">"Kudeatu baimenak"</string>
-    <string name="recent_access_time_content_descritption" msgid="1709675393952226273">"Denbora: %s"</string>
+    <string name="recent_access_time_content_descritption" msgid="1709675393952226273">"Ordua: %s"</string>
     <string name="activity_category_uppercase" msgid="136628843341377088">"Jarduerak"</string>
     <string name="activity_category_lowercase" msgid="3007220578865400601">"jarduerak"</string>
     <string name="body_measurements_category_uppercase" msgid="422923782603313038">"Gorputzaren neurketak"</string>
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Aktibo egondako denbora, ariketa mota, itzuliak, errepikapenak, saioak, besakadak eta antzeko informazioa sartzen da datuetan"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Lo-faseak eta -saioak, eta antzeko informazioa sartzen da datuetan"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Ikusi sarrera guztiak"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"aldatu"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Ezabatu datuak"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"atzitu osasunari buruzko datuak"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ariketari dagokion ibilbidea"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Idatzi ariketari dagokion ibilbidea"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Irakurri ariketaren ibilbidea"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Irakurri ariketei dagozkien ibilbideak"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distantzia"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distantzia"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Irakurri distantziari buruzko datuak"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"atsedeneko bihotz-maiztasuna"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Irakurri atsedeneko bihotz-maiztasunari buruzko datuak"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Idatzi atsedeneko bihotz-maiztasunari buruzko datuak"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Azalaren tenperatura"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"azalaren tenperatura"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Azalaren tenperatura irakurri"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Azalaren tenperatura idatzi"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Eman irakurtzeko baimena <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioari"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Eman idazteko baimena <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioari"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Utzi"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect-eko datuak ezabatzen"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect-eko datuak ezabatzen"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Datuak ezabatzea"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Ezabatu idatzitako datuak"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Ezabatu sarrera"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Ezabatu datu hauek: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Ezabatu sarrera hau: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Guztira: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Jaitsi"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Eraman goraino"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Eraman beheraino"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"<xliff:g id="SELECTED_APP">%s</xliff:g> lehentasunezkoen zerrendatik kentzeko botoia"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Ordena aldatzeko, sakatu birritan eta arrastatu"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitnessa, ongizatea"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"baimenak"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, osasunari buruzko datuak, osasunarekin erlazionatutako kategoriak, datuetarako sarbidea, jarduerak, gorputzaren neurketak, zikloen jarraipena, elikadura, loa, bizi-konstanteak"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Ariketei dagozkien ibilbideak erabiltzeko baimena duten aplikazioek soilik"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Nola kudea dezaket datuok erabiltzeko baimena?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Aplikazioek ariketei dagozkien ibilbideak erabiltzeko duten baimena kudeatzeko, joan Health Connect-en ezarpenetara"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Atzera"</string>
     <string name="loading" msgid="2526615755685950317">"Kargatzen…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integrazio-prozesua abian da"</string>
diff --git a/apk/res/values-fa/strings.xml b/apk/res/values-fa/strings.xml
index c3b04bb..53389de 100644
--- a/apk/res/values-fa/strings.xml
+++ b/apk/res/values-fa/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"این داده‌ها شامل اطلاعاتی مثل زمان فعالیت، نوع تمرین، دورها، تکرارها، جلسه‌ها، یا حرکت‌های شنا می‌شود"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"این داده‌ها شامل اطلاعاتی مثل مراحل خواب و جلسات خواب می‌شود"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"دیدن همه ورودی‌ها"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"تغییر"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"حذف این داده"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"دسترسی به داده‌های سلامت شما"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"مسیر تمرین"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"نوشتن مسیر تمرین"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"خواندن مسیر تمرین"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"خواندن همه مسیرهای تمرین"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"مسافت"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"مسافت"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"خواندن داده مسافت"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"ضربان قلب حین استراحت"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"خواندن داده ضربان قلب حین استراحت"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"نوشتن داده ضربان قلب حین استراحت"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"دمای پوست"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"دمای پوست"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"خواندن دمای پوست"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"نوشتن دمای پوست"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"اجازه دادن به «<xliff:g id="APP_NAME">%1$s</xliff:g>» برای خواندن"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"اجازه دادن به «<xliff:g id="APP_NAME">%1$s</xliff:g>» برای نوشتن"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"لغو کردن"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"درحال حذف داده‌های Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"درحال حذف داده‌های Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"حذف داده"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"حذف ورودی داده"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"حذف ورودی"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"حذف ورودی داده <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"حذف ورودی <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"مجموع: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{یک وات}one{# وات}other{# وات}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{یک وات}one{# وات}other{# وات}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"انتقال به‌پایین"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"انتقال به ابتدا"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"انتقال به انتها"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"دکمه برداشتن <xliff:g id="SELECTED_APP">%s</xliff:g> از فهرست اولویت"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"برای تغییر ترتیب، دوضربه بزنید و بکشید"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"تناسب اندام، تندرستی"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"اجازه‌ها"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect، داده‌های سلامت، دسته‌های سلامت، دسترسی به داده‌ها، فعالیت، سنجه‌های بدن، پیگیری قاعدگی، تغذیه، خواب، علائم حیاتی"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"فقط برنامه‌هایی که به آن‌ها اجازه می‌دهید به مسیرهای تمرین شما دسترسی داشته باشند"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"چگونه می‌توانم دسترسی را مدیریت کنم؟"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"در تنظیمات Health Connect می‌توانید دسترسی برنامه‌ها به مسیرهای تمرین را مدیریت کنید"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"برگشت"</string>
     <string name="loading" msgid="2526615755685950317">"درحال بار کردن…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"یکپارچه‌سازی درحال انجام است"</string>
diff --git a/apk/res/values-fi/strings.xml b/apk/res/values-fi/strings.xml
index 34b99f7..06ecb8a 100644
--- a/apk/res/values-fi/strings.xml
+++ b/apk/res/values-fi/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Data sisältää aktiivisuusajan, harjoitustyypin, kierrosten, toistojen, harjoituskertojen ja uintityylin kaltaisia tietoja"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Data sisältää univaiheiden ja unikertojen kaltaisia tietoja"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Katso kaikki merkinnät"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"muuta"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Poista data"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"pääsy terveysdataan"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"liikuntareitti"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Kirjoittaa liikuntareitin"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Lue liikuntareitti"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Lue kaikki harjoitusreitit"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Etäisyys"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"etäisyys"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Lukee etäisyysdataa"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"leposyke"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Lukee leposykedataa"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Kirjoittaa leposykedataa"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Ihon lämpötila"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"ihon lämpötila"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Lue ihon lämpötila"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Kirjoita ihon lämpötila"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Salli sovelluksen “<xliff:g id="APP_NAME">%1$s</xliff:g>” lukea"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Salli sovelluksen “<xliff:g id="APP_NAME">%1$s</xliff:g>” kirjoittaa"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Peru"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Poistetaan Health Connect ‑dataa"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Poistetaan Health Connect ‑dataa"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Datan poistaminen"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Poista datamerkintä"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Poista merkintä"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Poista datamerkintä: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Poista merkintä: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Yhteensä: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watti}other{# watti}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Siirrä alas"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Siirrä ylös"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Siirrä loppuun"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Painike, jolla <xliff:g id="SELECTED_APP">%s</xliff:g> poistuu tärkeiden listalta"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Järjestä uudelleen: kaksoisnapauta ja vedä"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"kuntoilu, hyvinvointi"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"luvat"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, terveysdata, terveyskategoriat, datan pääsyoikeudet, toiminta, kehon mittaustulokset, kierron seuranta, ravitsemus, uni, elintoiminnot"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Vain sovellukset, joille myönnät pääsyn harjoitusreitteihin"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Miten voin ylläpitää pääsyä?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Voit ylläpitää sovellusten pääsyä harjoitusreitteihin Health Connectin asetuksissa"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Takaisin"</string>
     <string name="loading" msgid="2526615755685950317">"Ladataan…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integrointi käynnissä"</string>
diff --git a/apk/res/values-fr-rCA/strings.xml b/apk/res/values-fr-rCA/strings.xml
index d0b3008..35ef77d 100644
--- a/apk/res/values-fr-rCA/strings.xml
+++ b/apk/res/values-fr-rCA/strings.xml
@@ -45,8 +45,7 @@
     <string name="write_data_access_label" msgid="7955988316773000250">"Écriture : %s"</string>
     <string name="data_type_separator" msgid="1299848322898210658">", "</string>
     <string name="manage_permissions" msgid="8394221950712608160">"Gérer les autorisations"</string>
-    <!-- no translation found for recent_access_time_content_descritption (1709675393952226273) -->
-    <skip />
+    <string name="recent_access_time_content_descritption" msgid="1709675393952226273">"Temps : %s"</string>
     <string name="activity_category_uppercase" msgid="136628843341377088">"Activité"</string>
     <string name="activity_category_lowercase" msgid="3007220578865400601">"activité"</string>
     <string name="body_measurements_category_uppercase" msgid="422923782603313038">"Mensurations"</string>
@@ -76,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Ces données incluent des informations telles que la durée d\'activité, le type d\'exercice, le nombre de tours, les répétitions, les séances ou les mouvements de nage"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Ces données incluent des informations telles que les phases de sommeil et les périodes de sommeil"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Afficher toutes les entrées"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"modifier"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Supprimer ces données"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Connexion santé"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"accéder à vos données de santé"</string>
@@ -96,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"l\'itinéraire d\'exercice"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Écriture des données relatives à l\'itinéraire d\'exercice"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Lecture des données relatives à l\'itinéraire d\'exercice"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Lire tous les itinéraires d\'exercice"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distance"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distance"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Lecture des données relatives à la distance"</string>
@@ -241,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"la fréquence cardiaque au repos"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Lecture des données relatives à la fréquence cardiaque au repos"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Écriture des données relatives à la fréquence cardiaque au repos"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Température cutanée"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"température cutanée"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Lire la température cutanée"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Écrire la température cutanée"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Autoriser la lecture des données par « <xliff:g id="APP_NAME">%1$s</xliff:g> »"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Autoriser l\'écriture des données par « <xliff:g id="APP_NAME">%1$s</xliff:g> »"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Annuler"</string>
@@ -348,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Suppression de données Connexion santé en cours…"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Suppression de données Connexion santé en cours…"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Suppression de données"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Supprimez les entrées de données"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Supprimer l\'entrée"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Supprimer l\'entrée de données <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Supprimer l\'entrée <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total : <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}one{# watt}other{# watts}}"</string>
@@ -711,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Déplacer vers le bas"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Placer en première position"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Placer en dernière position"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Bouton pour retirer <xliff:g id="SELECTED_APP">%s</xliff:g> de la liste de priorité"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Toucher deux fois et glisser pour réorganiser"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"mise en forme, bien-être"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"autorisations"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"connexion santé, données de santé, catégories de santé, accès aux données, activité, mensurations, suivi du cycle, nutrition, sommeil, signes vitaux."</string>
@@ -727,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Uniquement les applications que vous autorisez à accéder à vos itinéraires d\'exercice"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Comment puis-je gérer l\'accès?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Vous pouvez gérer l\'accès des applications aux itinéraires d\'exercices dans les paramètres de Connexion santé"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Retour"</string>
     <string name="loading" msgid="2526615755685950317">"Chargement en cours…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Intégration en cours…"</string>
diff --git a/apk/res/values-fr/strings.xml b/apk/res/values-fr/strings.xml
index a9a1215..e6867be 100644
--- a/apk/res/values-fr/strings.xml
+++ b/apk/res/values-fr/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Ces données incluent des informations comme la durée d\'activité, le type d\'exercice, les tours, les répétitions, les sessions ou les mouvements de nage"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Ces données incluent des informations comme les phases et les sessions de sommeil"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Voir toutes les entrées"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"modifier"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Supprimer ces données"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Santé Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"accéder à vos données de forme physique"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"parcours sportif"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Écrire le parcours sportif"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Lire le parcours sportif"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Lire tous les parcours sportifs"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distance"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distance"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Lire la distance"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"fréquence cardiaque au repos"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Lire la fréquence cardiaque au repos"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Modifier la fréquence cardiaque au repos"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Température cutanée"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"température cutanée"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Lire la température cutanée"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Indiquer la température cutanée"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Autoriser <xliff:g id="APP_NAME">%1$s</xliff:g> à lire"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Autoriser <xliff:g id="APP_NAME">%1$s</xliff:g> à écrire"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Annuler"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Suppression des données Santé Connect…"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Suppression des données Santé Connect…"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Suppression des données…"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Supprimer la saisie de données"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Supprimer l\'entrée"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Supprimer la saisie de données <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Supprimer l\'entrée <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total : <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}one{# watt}other{# watts}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Déplacer vers le bas"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Première position"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Dernière position"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Bouton pour supprimer <xliff:g id="SELECTED_APP">%s</xliff:g> de la liste des priorités"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Appuyez deux fois et faites glisser pour réorganiser"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"remise en forme, bien-être"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"autorisations"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Santé Connect, données de forme physique, catégories de santé, accès aux données, activité, données corporelles, suivi du cycle, nutrition, sommeil, constantes"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Seules les applis que vous autorisez à accéder à vos parcours sportifs"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Comment puis-je gérer l\'accès ?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Vous pouvez gérer l\'accès de cette appli aux parcours sportifs dans les paramètres Santé Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Retour"</string>
     <string name="loading" msgid="2526615755685950317">"Chargement…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Intégration en cours"</string>
diff --git a/apk/res/values-gl/strings.xml b/apk/res/values-gl/strings.xml
index 57e5dab..192ddcf 100644
--- a/apk/res/values-gl/strings.xml
+++ b/apk/res/values-gl/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Estes datos inclúen determinada información, como o tempo de actividade, o tipo de exercicio, as voltas, as repeticións, as sesións ou as brazadas"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Estes datos inclúen determinada información, como as fases e as sesións de sono"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Ver todas as entradas"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"fai un cambio"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Eliminar estes datos"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Saúde conectada"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"acceder aos datos sobre a túa saúde"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ruta do exercicio"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Escribir datos da ruta do exercicio"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Ler ruta do exercicio"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Ler todas as rutas de exercicio"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distancia"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distancia"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Ler datos de distancia"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"frecuencia cardíaca en repouso"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Ler datos de frecuencia cardíaca en repouso"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Escribir datos de frecuencia cardíaca en repouso"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura cutánea"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura cutánea"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Ler temperatura cutánea"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Escribir temperatura cutánea"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Permitir que <xliff:g id="APP_NAME">%1$s</xliff:g> lea"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Permitir que <xliff:g id="APP_NAME">%1$s</xliff:g> escriba"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Cancelar"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Eliminando datos de Saúde conectada"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Eliminando datos de Saúde conectada"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Eliminación de datos"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Eliminar entrada de datos"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Eliminar entrada"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Eliminar a entrada de datos <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Eliminar entrada: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watts}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Mover cara abaixo"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Mover para arriba de todo"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Mover para abaixo de todo"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Botón para quitar <xliff:g id="SELECTED_APP">%s</xliff:g> da lista prioritaria"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Toca dúas veces e arrastra para reordenar"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"forma física, benestar"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"permisos"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"saúde conectada, datos sobre a saúde, categorías de saúde, acceso a datos, actividade, medicións corporais, seguimento do ciclo menstrual, nutrición, sono, constantes vitais"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Só as aplicacións ás que lles permitas acceder ás túas rutas de exercicio"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Como podo xestionar o acceso?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Podes xestionar o acceso das aplicacións ás rutas de exercicio na configuración de Saúde conectada"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Atrás"</string>
     <string name="loading" msgid="2526615755685950317">"Cargando…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integración en proceso"</string>
diff --git a/apk/res/values-gu/strings.xml b/apk/res/values-gu/strings.xml
index 76bad3b..9f35c1a 100644
--- a/apk/res/values-gu/strings.xml
+++ b/apk/res/values-gu/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"આ ડેટામાં સક્રિય સમય, વ્યાયામનો પ્રકાર, લૅપ, પુનરાવર્તનો, સત્રો અથવા સ્વિમિંગ સ્ટ્રોક જેવી માહિતી શામેલ છે"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"આ ડેટામાં ઊંઘના તબક્કા અને ઊંઘના સત્રો જેવી માહિતી શામેલ છે"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"બધી એન્ટ્રી જુઓ"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"બદલો"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"આ ડેટા ડિલીટ કરો"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"તમારો આરોગ્ય સંબંધિત ડેટા ઍક્સેસ કરો"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"વ્યાયામનો રસ્તો"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"વ્યાયામનો રસ્તો બનાવો"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"વ્યાયામ કરવાની રીત વિશેની માહિતી વાંચવી"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"વ્યાયામના તમામ રસ્તા વાંચો"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"અંતર"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"અંતર"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"અંતરનો ડેટા વાંચો"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"આરામ કરતી વખતે હૃદયના ધબકારા"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"આરામ કરતી વખતના હૃદયના ધબકારાનો ડેટા વાંચો"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"આરામ કરતી વખતના હૃદયના ધબકારાનો ડેટા લખો"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"ત્વચાનું તાપમાન"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"ત્વચાનું તાપમાન"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"ત્વચાના તાપમાનનો ડેટા વાંચો"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"ત્વચાના તાપમાનનો ડેટા લખો"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”ને વાંચવાની મંજૂરી આપો"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”ને લખવાની મંજૂરી આપો"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"રદ કરો"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connectના ડેટાને ડિલીટ કરી રહ્યાં છીએ"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connectના ડેટાને ડિલીટ કરી રહ્યાં છીએ"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"ડેટા ડિલીટ કરવો"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"ડેટા એન્ટ્રી ડિલીટ કરો"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"એન્ટ્રી ડિલીટ કરો"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ડેટા એન્ટ્રી ડિલીટ કરો"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> એન્ટ્રી ડિલીટ કરો"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"કુલ: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 વૉટ}one{# વૉટ}other{# વૉટ}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 વૉટ}one{# વૉટ}other{# વૉટ}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"નીચે ખસેડો"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"સૌથી ઉપર ખસેડો"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"સૌથી નીચે ખસેડો"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"પ્રાધાન્યતા સૂચિમાંથી <xliff:g id="SELECTED_APP">%s</xliff:g> કાઢી નાખવા માટેનું બટન"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"ક્રમમાં ફેરફાર કરવા માટે બે વાર ટૅપ કરો અને ખેંચો"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ફિટનેસ, સુખાકારી"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"પરવાનગીઓ"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, હેલ્થ ડેટા, હેલ્થ કૅટેગરી, ડેટા ઍક્સેસ, પ્રવૃત્તિ, શરીરના માપ, સાઇકલ ટ્રૅકિંગ, પોષણ, ઊંઘ, આરોગ્ય વિશેની મહત્ત્વપૂર્ણ માહિતી"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"માત્ર એ ઍપ જેમને તમે તમારા વ્યાયામના રસ્તાને ઍક્સેસ કરવાની મંજૂરી આપો છો"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"હું ઍક્સેસ કેવી રીતે મેનેજ કરી શકું?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"તમે Health Connectના સેટિંગમાં જઈને વ્યાયામના રસ્તા માટેના ઍપના ઍક્સેસને મેનેજ કરી શકો છો"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"પાછળ"</string>
     <string name="loading" msgid="2526615755685950317">"લોડ કરી રહ્યાં છીએ…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"એકીકરણની પ્રક્રિયા ચાલુ છે"</string>
diff --git a/apk/res/values-hi/strings.xml b/apk/res/values-hi/strings.xml
index 7577cb2..717bea2 100644
--- a/apk/res/values-hi/strings.xml
+++ b/apk/res/values-hi/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"इस डेटा में कई तरह की जानकारी शामिल होती है. जैसे, कसरत का कुल समय, किस तरह की कसरत की गई, कितने लैप किए गए, कसरत कितनी बार दोहराई गई, कितने सेशन या स्विमिंग स्ट्रोक किए"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"इस डेटा में, नींद के चरण और इसके सेशन वगैरह की जानकारी शामिल होती है"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"सभी एंट्री देखें"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"बदलें"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"यह डेटा मिटाएं"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"आपके स्वास्थ्य की जानकारी से जुड़ा डेटा ऐक्सेस करने की अनुमति दें"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"कसरत का रूट"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"कसरत का रूट बनाएं"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"कसरत का रूट पढ़ें"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"कसरत के सभी रूट पढ़ें"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"दूरी का डेटा"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"दूरी का डेटा"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"तय की गई दूरी का डेटा पढ़ने की अनुमति दें"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"आराम करते समय धड़कन की दर का डेटा"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"आराम करते समय धड़कन की दर का डेटा पढ़ने की अनुमति दें"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"आराम करते समय धड़कन की दर का डेटा सेव करने की अनुमति दें"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"त्वचा का तापमान"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"त्वचा का तापमान"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"त्वचा के तापमान से जुड़ी जानकारी देखें"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"त्वचा के तापमान से जुड़ी जानकारी में बदलाव करें"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” को डेटा पढ़ने की अनुमति दें"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” को डेटा में बदलाव करने की अनुमति दें"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"रद्द करें"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect का डेटा मिटाया जा रहा है"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect का डेटा मिटाया जा रहा है"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"डेटा मिटाना"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"सबमिट किए गए डेटा को मिटाएं"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"एंट्री मिटाएं"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> वाली डेटा एंट्री मिटाएं"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> वाली एंट्री मिटाएं"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"कुल: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 वॉट}one{# वॉट}other{# वॉट}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 वॉट}one{# वॉट}other{# वॉट}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"नीचे ले जाएं"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"सबसे ऊपर ले जाएं"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"सबसे नीचे ले जाएं"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"प्राथमिकता सूची से <xliff:g id="SELECTED_APP">%s</xliff:g> को हटाने का बटन"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"क्रम बदलने के लिए, दो बार टैप करके ड्रैग करें"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"फ़िटनेस, सेहत"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"अनुमतियां"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, स्वास्थ्य की जानकारी से जुड़ा डेटा, स्वास्थ्य की कैटगरी, डेटा ऐक्सेस, गतिविधि, शरीर की माप, पीरियड साइकल को ट्रैक करना, पोषण, नींद, शरीर से जुड़ी ज़रूरी जानकारी"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"सिर्फ़ वे ऐप्लिकेशन जिन्हें आपने कसरत के रूट ऐक्सेस करने की अनुमति दी है"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"मैं ऐक्सेस कैसे मैनेज करूं?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Health Connect की सेटिंग में जाकर, कसरत के रूट के लिए ऐप्लिकेशन का ऐक्सेस मैनेज किया जा सकता है"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"वापस जाएं"</string>
     <string name="loading" msgid="2526615755685950317">"लोड हो रहा है…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"इंटिग्रेट किया जा रहा है"</string>
diff --git a/apk/res/values-hr/strings.xml b/apk/res/values-hr/strings.xml
index fbdd99c..bab74b7 100644
--- a/apk/res/values-hr/strings.xml
+++ b/apk/res/values-hr/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Ovi podaci uključuju informacije kao što su aktivno vrijeme, vrsta vježbe, krugovi, ponavljanja, sesije ili plivački zamasi"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Ovi podaci uključuju informacije kao što su faze spavanja i sesije spavanja"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Pogledajte sve unose"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"promijeni"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Izbriši ove podatke"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"pristup podacima o zdravlju"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ruta za vježbanje"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Zapiši rutu za vježbanje"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Očitaj rutu vježbe"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Čitaj sve rute za vježbu"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Udaljenost"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"udaljenost"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Očitavanje udaljenosti"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"puls u mirovanju"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Očitavanje pulsa u mirovanju"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Bilježenje pulsa u mirovanju"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura kože"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura kože"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Očitavanje temperature kože"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Zapisivanje temperature kože"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Dopusti aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> da očita"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Dopusti aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> da zapiše"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Odustani"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Brisanje podataka Health Connecta"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Brisanje podataka Health Connecta"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Brisanje podataka"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Brisanje unosa podataka"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Izbriši unos"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Brisanje unosa podataka <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Brisanje unosa <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Ukupno: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}few{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vat}one{# vat}few{# vata}other{# vata}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Premjesti dolje"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Premjesti na vrh"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Premjesti na dno"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Gumb za uklanjanje aplikacije <xliff:g id="SELECTED_APP">%s</xliff:g> s popisa prioriteta"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Dodirnite dvaput i povucite za promjenu poretka"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"dopuštenja"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, podaci o zdravlju, kategorije zdravlja, pristup podacima, aktivnost, tjelesne mjere, praćenje ciklusa, prehrana, spavanje, vitalni znakovi"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Samo aplikacije kojima omogućite pristup rutama za vježbu"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Kako mogu upravljati pristupom?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Možete upravljati pristupom aplikacije rutama za vježbu u postavkama Health Connecta"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Natrag"</string>
     <string name="loading" msgid="2526615755685950317">"Učitavanje…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integracija u tijeku"</string>
diff --git a/apk/res/values-hu/strings.xml b/apk/res/values-hu/strings.xml
index 9514b46..004e425 100644
--- a/apk/res/values-hu/strings.xml
+++ b/apk/res/values-hu/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Ezek az adatok olyan információkat tartalmaznak, mint az aktív idő, a testmozgás típusa, a körök, ismétlések, edzések száma, valamint a csapásszámok"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Ezek az adatok olyan információkat tartalmaznak, mint az alvási fázisok és az alvásidőszakok"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Minden bejegyzés megtekintése"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"módosítás"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Az ilyen adatok törlése"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"hozzáférés az egészségügyi adataihoz"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"edzésútvonal"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Edzésútvonal írása"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Edzésútvonal áttekintése"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Az összes edzésútvonal olvasása"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Távolság"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"távolság"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Távolságra vonatkozó adatok olvasása"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"nyugalmi pulzusszám"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Nyugalmi pulzusszámra vonatkozó adatok olvasása"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Nyugalmi pulzusszámra vonatkozó adatok írása"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Bőrhőmérséklet"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"bőrhőmérséklet"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Bőrhőmérséklet olvasása"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Bőrhőmérséklet írása"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Olvasási jogosultság a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazásnak"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Írási jogosultság a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazásnak"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Mégse"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect-adatok törlése"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect-adatok törlése"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Adatok törlése"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Adatbevitel törlése"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Bejegyzés törlése"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Adatbevitel törlése: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Bejegyzés törlése: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Összesen: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Mozgatás lefelé"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Áthelyezés az elejére"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Áthelyezés a végére"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"A(z) <xliff:g id="SELECTED_APP">%s</xliff:g> appot a prioritási listáról eltávolító gomb"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Koppintson duplán és húzza az átrendezéshez"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitnesz, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"engedélyek"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, egészségügyi adatok, egészségügyi kategóriák, adathozzáférés, tevékenységek, testméretek, cikluskövetés, táplálkozás, alvás, életfunkciók"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Csak azok az alkalmazások, amelyek számára engedélyezte az edzésútvonalakhoz való hozzáférést"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Hogyan kezelhetem a hozzáférést?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Az alkalmazások edzésútvonalakhoz való hozzáférését a Health Connect beállításai között kezelheti."</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Vissza"</string>
     <string name="loading" msgid="2526615755685950317">"Betöltés…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Az integráció folyamatban van"</string>
diff --git a/apk/res/values-hy/strings.xml b/apk/res/values-hy/strings.xml
index ff04694..c752044 100644
--- a/apk/res/values-hy/strings.xml
+++ b/apk/res/values-hy/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Այս տվյալները ներառում են տեղեկություններ, օրինակ, ակտիվ ժամանակի, վարժության տեսակի, պտույտների, կրկնությունների, ժամանակահատվածների և լողալու ընթացքում թիահարվածների մասին"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Այս տվյալները ներառում են տեղեկություններ, օրինակ, քնի փուլերի և քնի ժամանակահատվածների մասին"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Տեսնել բոլոր տվյալները"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"փոխել"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Ջնջել այս տվյալները"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"ձեր առողջության մասին տվյալների հասանելիություն"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"մարզումների երթուղի"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Գրանցել մարզումների երթուղին"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Կարդալ մարզման եղանակների մասին տեղեկություններ"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Կարդալ մարզումների բոլոր երթուղիները"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Հեռավորություն"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"հեռավորություն"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Կարդալ անցած հեռավորության մասին տվյալները"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"սրտի զարկերի հաճախականությունը հանգիստ վիճակում"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Կարդալ հանգիստ վիճակում սրտի զարկերի հաճախականության մասին տվյալները"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Գրանցել հանգիստ վիճակում սրտի զարկերի հաճախականության մասին տվյալները"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Մարմնի ջերմաստիճանը"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"մարմնի ջերմաստիճանը"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Կարդալ մարմնի ջերմաստիճանի տվյալները"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Գրել մարմնի ջերմաստիճանի տվյալները"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Թույլատրել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածին կարդալ"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Թույլատրել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածին գրանցել"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Չեղարկել"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect-ի տվյալները ջնջվում են"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect-ի տվյալները ջնջվում են"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Տվյալների ջնջում"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Ջնջել մուտքագրված տվյալները"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Ջնջել գրառումը"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Ջնջել գրառումը՝ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Ջնջել գրառումը՝ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Ընդամենը՝ <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 Վտ}one{# Վտ}other{# Վտ}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 վատտ}one{# վատտ}other{# վատտ}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Տեղափոխել ներքև"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Տեղափոխել սկիզբ"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Տեղափոխել վերջ"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"<xliff:g id="SELECTED_APP">%s</xliff:g>-ն առաջնահերթության ցանկից հեռացնելու կոճակ"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Կրկնակի հպեք և քաշեք՝ վերադասավորելու համար"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ֆիթնես, առողջություն"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"թույլտվություններ"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, առողջության մասին տվյալներ, առողջության կատեգորիաներ, տվյալների հասանելիություն, գործողություններ, մարմնի պարամետրեր, ցիկլի հետագծում, սնունդ, քուն, կենսական ցուցանիշներ"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Միայն հավելվածները, որոնց հասանելի են ձեր մարզումների երթուղիները"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Ինչպե՞ս կարող եմ կառավարել երթուղու հասանելիությունը"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Մարզումների երթուղիների հասանելիությունը հավելվածների համար կարող եք կառավարել Health Connect-ի կարգավորումներում"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Հետ"</string>
     <string name="loading" msgid="2526615755685950317">"Բեռնում…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Ինտեգրումն ընթացքում է"</string>
diff --git a/apk/res/values-in/strings.xml b/apk/res/values-in/strings.xml
index d3606fd..1d85d6f 100644
--- a/apk/res/values-in/strings.xml
+++ b/apk/res/values-in/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Data ini termasuk informasi seperti waktu aktif, jenis olahraga, putaran, repetisi, sesi, atau gaya renang"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Data ini termasuk informasi seperti fase tidur dan sesi tidur"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Lihat semua entri"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"ubah"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Hapus data ini"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"mengakses data kesehatan Anda"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"rute olahraga"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Tulis rute olahraga"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Baca rute olahraga"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Baca semua rute olahraga"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Jarak"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"jarak"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Baca jarak"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"detak jantung saat istirahat"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Baca detak jantung saat istirahat"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Tulis detak jantung saat istirahat"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Suhu kulit"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"suhu kulit"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Membaca suhu kulit"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Menulis suhu kulit"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Izinkan “<xliff:g id="APP_NAME">%1$s</xliff:g>” untuk membaca"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Izinkan “<xliff:g id="APP_NAME">%1$s</xliff:g>” untuk menulis"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Batal"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Menghapus data Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Menghapus data Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Penghapusan data"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Hapus entri data"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Hapus entri"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Hapus entri data <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Hapus entri <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Geser ke bawah"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Pindahkan ke atas"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Pindahkan ke bawah"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Tombol untuk menghapus <xliff:g id="SELECTED_APP">%s</xliff:g> dari daftar prioritas"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Ketuk dua kali dan tarik untuk mengurutkan ulang"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"kebugaran, kesehatan"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"izin"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, data kesehatan, kategori kesehatan, akses data, aktivitas, pengukuran tubuh, pencatatan siklus, nutrisi, tidur, tanda vital"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Hanya aplikasi yang Anda izinkan mengakses rute latihan"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Bagaimana cara mengelola akses?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Anda dapat mengelola akses aplikasi ke rute latihan di setelan Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Kembali"</string>
     <string name="loading" msgid="2526615755685950317">"Memuat …"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integrasi sedang berlangsung"</string>
diff --git a/apk/res/values-is/strings.xml b/apk/res/values-is/strings.xml
index 80d8f59..b99a2f4 100644
--- a/apk/res/values-is/strings.xml
+++ b/apk/res/values-is/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Þessi gögn innihalda upplýsingar á borð við hreyfingartíma, tegund æfinga, umferðir, endurtekningar, lotur eða sundtök"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Þessi gögn innihalda upplýsingar á borð við svefnstig og svefnlotur"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Sjá allar færslur"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"breyta"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Eyða þessum gögnum"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Heilsutenging"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"opna heilsugögn"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"æfingaleið"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Skrifa æfingaleið"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Lesa æfingaleið"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Lesa allar æfingaleiðir"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Vegalengd"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"vegalengd"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Lesa vegalengd"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"hjartsláttur í hvíld"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Lesa hjartslátt í hvíld"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Skrifa hjartslátt í hvíld"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Hitastig húðar"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"hitastig húðar"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Lesa hitastig húðar"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Skrifa hitastig húðar"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Leyfa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ að lesa"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Leyfa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ að skrifa"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Hætta við"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Eyðir gögnum Heilsutengingar"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Eyðir gögnum Heilsutengingar"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Gagnaeyðing"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Eyða gagnaskráningu"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Eyða færslu"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Eyða færslunni „<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>“"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Eyða færslunni „<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>“"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Alls: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 V}one{# V}other{# V}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vatt}one{# vatt}other{# vött}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Færa niður"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Færa efst"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Færa neðst"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Hnappur til að fjarlægja <xliff:g id="SELECTED_APP">%s</xliff:g> af forgangslista"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Ýttu tvisvar og dragðu til að endurraða"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"hreysti, vellíðan"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"heimildir"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"heilsutenging, heilsugögn, heilsuflokkar, aðgangur að gögnum, hreyfing, líkamsmælingar, skráning tíðahrings, næring, svefn, lífsmörk"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Aðeins forrit sem þú veitir aðgang að æfingaleiðunum þínum"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Hvernig stjórna ég aðgangi?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Þú getur stjórnað aðgangi forrita að æfingaleiðum í stillingum Heilsutengingar"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Til baka"</string>
     <string name="loading" msgid="2526615755685950317">"Hleður…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Samþætting í gangi"</string>
diff --git a/apk/res/values-it/strings.xml b/apk/res/values-it/strings.xml
index 17e6345..ae4c0e6 100644
--- a/apk/res/values-it/strings.xml
+++ b/apk/res/values-it/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Questi dati includono informazioni come il tempo di attività, il tipo di esercizio, i giri, le ripetizioni, le sessioni o le bracciate"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Questi dati includono informazioni come le fasi del sonno e le sessioni di sonno"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Visualizza tutte le voci"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"modifica"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Elimina questi dati"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Connessione Salute"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"accesso ai dati relativi alla salute"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"percorso per l\'esercizio fisico"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Scrittura del percorso per l\'esercizio fisico"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Lettura del percorso per l\'esercizio fisico"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Leggi tutti i tuoi percorsi per l\'esercizio fisico"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distanza"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distanza"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Lettura della distanza"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"battito cardiaco a riposo"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Lettura del battito cardiaco a riposo"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Scrittura del battito cardiaco a riposo"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura cutanea"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura cutanea"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Leggere la temperatura cutanea"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Scrivere la temperatura cutanea"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Consenti lettura all\'app \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Consenti scrittura all\'app \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Annulla"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Eliminazione dati Connessione Salute in corso…"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Eliminazione dati Connessione Salute in corso…"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Eliminazione dei dati"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Elimina immissione dati"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Elimina voce"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Elimina immissione dati <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Elimina voce <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Totale: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Sposta giù"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Sposta su"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Sposta alla fine"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Pulsante per rimuovere <xliff:g id="SELECTED_APP">%s</xliff:g> dall\'elenco di priorità"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Tocca due volte e trascina per cambiare l\'ordine"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"attività fisica, benessere"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"autorizzazioni"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"connessione salute, dati salute, categorie salute, accesso ai dati, attività, misurazioni corporee, monitoraggio del ciclo, alimentazione, sonno, parametri vitali"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Soltanto le app a cui consenti l\'accesso ai tuoi percorsi per l\'esercizio fisico"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Come faccio a gestire l\'accesso?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Puoi gestire l\'accesso delle app ai percorsi per l\'esercizio fisico nelle impostazioni di Connessione Salute"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Indietro"</string>
     <string name="loading" msgid="2526615755685950317">"Caricamento in corso…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integrazione in corso"</string>
diff --git a/apk/res/values-iw/strings.xml b/apk/res/values-iw/strings.xml
index 4b07c7c..6e9d63c 100644
--- a/apk/res/values-iw/strings.xml
+++ b/apk/res/values-iw/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"הנתונים האלה כוללים מידע כמו משך הפעילות, סוג האימון, הקפות, חזרות, סשנים או חתירות בשחייה"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"הנתונים האלה כוללים מידע כמו שלבי השינה וסשנים של שינה"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"לעיון בכל הרשומות"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"שינוי"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"מחיקת הנתונים האלה"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"גישה לנתוני הבריאות שלך"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"מסלול האימון"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"כתיבה של נתוני מסלול האימון"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"קריאת הנתונים של מסלול האימון"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"קריאת כל הנתונים של מסלולי האימון"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"מרחק"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"מרחק"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"קריאה של נתוני המרחק"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"הדופק במנוחה"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"קריאה של נתוני הדופק במנוחה"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"כתיבה של נתוני הדופק במנוחה"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"טמפרטורת העור"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"טמפרטורת העור"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"קריאה של טמפרטורת העור"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"כתיבה של טמפרטורת העור"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"מתן הרשאה לאפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לקרוא נתונים"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"מתן הרשאה לאפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לכתוב נתונים"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"ביטול"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"הנתונים מ-Health Connect נמחקים"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"הנתונים מ-Health Connect נמחקים"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"מחיקת נתונים"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"מחיקת רשומת הנתונים"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"מחיקת רשומה"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"מחיקת רשומת הנתונים <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"מחיקת הרשומה <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"סה\"כ: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 ואט}one{# ואט}two{# ואט}other{# ואט}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ואט}one{# ואט}two{# ואט}other{# ואט}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"העברה למטה"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"העברה לראש הרשימה"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"העברה לתחתית הרשימה"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"לחצן להסרת <xliff:g id="SELECTED_APP">%s</xliff:g> מרשימת העדיפויות של האפליקציות"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"כדי לשנות את הסדר, מקישים הקשה כפולה וגוררים"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"כושר גופני, איכות חיים"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"הרשאות"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, נתוני בריאות, קטגוריות בריאות, גישה לנתונים, פעילות, מדדים גופניים, מעקב אחר המחזור, תזונה, שינה, סימנים חיוניים"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"רק לאפליקציות שנתת להן הרשאת גישה למסלולי האימון שלך"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"איך אוכל לנהל את הרשאות הגישה?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"אפשר לנהל את הרשאות הגישה של האפליקציות למסלולי אימון בהגדרות של Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"חזרה"</string>
     <string name="loading" msgid="2526615755685950317">"בטעינה…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"השילוב מתבצע"</string>
diff --git a/apk/res/values-ja/strings.xml b/apk/res/values-ja/strings.xml
index 2d3e7fd..8d5f3d5 100644
--- a/apk/res/values-ja/strings.xml
+++ b/apk/res/values-ja/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"このデータには、エクササイズの時間、エクササイズの種類、ラップ数、繰り返し数、セッション数、ストローク数(水泳)などの情報が含まれます"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"このデータには、睡眠ステージ、睡眠セッションなどの情報が含まれます"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"すべてのエントリを表示"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"変更"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"このデータを削除"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"ヘルスコネクト"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"健康に関するデータにアクセスします"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"エクササイズのルート"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"エクササイズのルートの書き込み"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"エクササイズのルートの読み込み"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"エクササイズのルートをすべて読み上げる"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"距離"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"距離"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"距離の読み取り"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"安静時の心拍数"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"安静時の心拍数の読み取り"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"安静時の心拍数の書き込み"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"皮膚温"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"皮膚温"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"皮膚温を読み取る"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"皮膚温を書き込む"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」に読み取りを許可する"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」に書き込みを許可する"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"キャンセル"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"ヘルスコネクトのデータの削除中"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"ヘルスコネクトのデータを削除しています"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"データの削除"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"データエントリを削除"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"エントリを削除"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"データエントリ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> を削除"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"エントリ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> を削除"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"合計: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ワット}other{# ワット}}"</string>
@@ -504,7 +510,7 @@
     <string name="activity_type_australian_football" msgid="431838050917315084">"オーストラリアン フットボール"</string>
     <string name="sleep_session_default" msgid="7376764686701487196">"<xliff:g id="DURATION"> %1$s</xliff:g> - 睡眠"</string>
     <string name="sleep_stage_default" msgid="1539043695578480733">"<xliff:g id="DURATION">%1$s</xliff:g> <xliff:g id="NAME">%2$s</xliff:g>⁠"</string>
-    <string name="sleep_stage_awake" msgid="4526767634444460862">"覚醒"</string>
+    <string name="sleep_stage_awake" msgid="4526767634444460862">"覚醒状態"</string>
     <string name="sleep_stage_awake_in_bed" msgid="5533385496857888503">"寝床で目が覚めている状態"</string>
     <string name="sleep_stage_sleeping" msgid="5122840110107303518">"睡眠"</string>
     <string name="sleep_stage_out_of_bed" msgid="522297068981578046">"起床"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"下に移動"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"一番上に移動"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"一番下に移動"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"優先度リストから<xliff:g id="SELECTED_APP">%s</xliff:g>を削除するボタンです"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"並べ替えるにはダブルタップしてドラッグします"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"フィットネス, 健康管理"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"権限"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"ヘルスコネクト, 健康に関するデータ, 健康に関するカテゴリ, データアクセス, アクティビティ, 身体測定, 月経周期の管理, 栄養, 睡眠, バイタル"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"エクササイズのルートへのアクセスを許可したアプリのみです"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"アクセスを管理するにはどうすればよいですか?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"エクササイズのルートへのアプリのアクセスはヘルスコネクトの設定で管理できます"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"戻る"</string>
     <string name="loading" msgid="2526615755685950317">"読み込んでいます…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"統合中"</string>
diff --git a/apk/res/values-ka/strings.xml b/apk/res/values-ka/strings.xml
index a88f09d..b67f7c5 100644
--- a/apk/res/values-ka/strings.xml
+++ b/apk/res/values-ka/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"ეს მონაცემები მოიცავს ინფორმაციას, როგორიცაა აქტიური დრო, ვარჯიშის ტიპი, წრეები, გამეორებები, სესიები ან საცურაო ხაზები."</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ეს მონაცემები მოიცავს ინფორმაციას, როგორიცაა ძილის ეტაპები და ძილის სესიები"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"ყველა მონაცემის ნახვა"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"შეცვლა"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"ამ მონაცემების წაშლა"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"თქვენს ჯანმრთელობის მონაცემებზე წვდომა"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"სავარჯიშო მარშრუტი"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"დაწერეთ სავარჯიშო მარშრუტი"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"ვარჯიშის მარშრუტის წაკითხვა"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"წაიკითხეთ ყველა სავარჯიშო მარშრუტი"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"მანძილი"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"მანძილი"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"მანძილის შესახებ ინფორმაციის წაკითხვა"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"გულისცემის სიხშირე მოსვენებისას"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"დასვენებისას გულისცემის სიხშირის შესახებ ინფორმაციის წაკითხვა"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"დასვენებისას გულისცემის სიხშირის შესახებ ინფორმაციის ჩაწერა"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"კანის ტემპერატურა"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"კანის ტემპერატურა"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"კანის ტემპერატურის წაკითხვა"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"კანის ტემპერატურის დაწერა"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"ნება მიეცით „<xliff:g id="APP_NAME">%1$s</xliff:g>“-ს, წაიკითხოს"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"ნება მიეცით „<xliff:g id="APP_NAME">%1$s</xliff:g>“-ს, წეროს"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"გაუქმება"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"მიმდინარებს Health Connect მონაცემების წაშლა"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"მიმდინარებს Health Connect მონაცემების წაშლა"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"მიმდინარეობს მონაცემების წაშლა"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"მონაცემთა ჩანაწერის წაშლა"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"შენატანის წაშლა"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"მონაცემთა ჩანაწერის წაშლა: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"ჩანაწერის წაშლა: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"სულ: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 ვტ}other{# ვტ}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ვატი}other{# ვატი}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"ქვემოთ გადატანა"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ზემოთ ატანა"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"ბოლოში ჩამოტანა"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"ღილაკი <xliff:g id="SELECTED_APP">%s</xliff:g>-ის ამოსაშლელად პრიორიტეტების სიიდან"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"გადასაწყობად ორმაგად შეეხეთ და ჩაავლეთ"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ფიტნესი, ველნესი"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"ნებართვები"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"ჯანმრთელობის დაკავშირება, ჯანმრთელობის მონაცემები, ჯანმრთელობის კატეგორიები, მონაცემების წვდომა, აქტივობა, სხეულის გაზომვები, ციკლის თვალყურის დევნება, კვება, ძილი, სასიცოცხლო მნიშვნელობები"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"მხოლოდ აპებს, რომელთაც წვდომას მიანიჭებთ სავარჯიშო მარშრუტზე"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"როგორ ვმართო წვდომა?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"სავარჯიშო მარშრუტებზე აპის წვდომის მართვა შეგიძლიათ Health Connect-ის პარამეტრებში"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"უკან"</string>
     <string name="loading" msgid="2526615755685950317">"მიმდინარეობს ჩატვირთვა…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"მიმდინარეობს ინტეგრაცია"</string>
diff --git a/apk/res/values-kk/strings.xml b/apk/res/values-kk/strings.xml
index 932f275..4b44835 100644
--- a/apk/res/values-kk/strings.xml
+++ b/apk/res/values-kk/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Бұл деректерге белсенді уақыт, жаттығу түрі, айналымдар, қайталау саны, сеанстар немесе жүзу қимылдары сияқты ақпарат кіреді."</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Бұл деректерге ұйқы кезеңдері мен сеанстары сияқты ақпарат кіреді."</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Барлық деректі көру"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"өзгерту"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Осы деректерді жою"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"денсаулық деректерін пайдалану рұқсаты"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"жаттығу бағыты"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Жаттығу бағытын жазу"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Жаттығу бағытын оқу"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Барлық жаттығу бағытын оқыңыз."</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Қашықтық"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"қашықтық"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Қашықтық деректерін оқу"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"тынығу кезіндегі жүрек қағысы"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Тынығу кезіндегі жүрек қағысы деректерін оқу"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Тынығу кезіндегі жүрек қағысы деректерін жазу"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Тері температурасы"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"тері температурасы"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Тері температурасын оқу"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Тері температурасын жазу"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" қолданбасына оқуға рұқсат беру"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" қолданбасына жазуға рұқсат беру"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Бас тарту"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect деректері жойылып жатыр"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect деректері жойылып жатыр."</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Деректерді жою"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Енгізілген деректерді жою"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Жазбаны жою"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> дерек жазбасын жою"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> жазбасын жою"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Барлығы: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 Вт}other{# Вт}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ватт}other{# ватт}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Төмен жылжыту"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Басына жылжыту"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Соңына жылжыту"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Маңыздылар тізімінен <xliff:g id="SELECTED_APP">%s</xliff:g> жою түймесі"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Ретін өзгерту үшін екі рет түртіп, сүйреңіз."</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"фитнес, сауықтыру"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"рұқсаттар"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, денсаулыққа қатысты деректер, денсаулыққа қатысты санаттар, деректерді пайдалану, әрекет, дене өлшемдері, циклді бақылау, тамақтану, ұйқы, тіршілік көрсеткіштері"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Жаттығу бағыттарын рұқсаты бар қолданбалар ғана пайдалана алады."</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Пайдалану рұқсатын қалай басқара аламын?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Қолданбаның жаттығу бағыттарын пайдалану рұқсатын Health Connect параметрлерінен басқара аласыз."</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Артқа"</string>
     <string name="loading" msgid="2526615755685950317">"Жүктеліп жатыр…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Біріктіру процесі орындалып жатыр"</string>
diff --git a/apk/res/values-km/strings.xml b/apk/res/values-km/strings.xml
index b5e1f75..4f31aaf 100644
--- a/apk/res/values-km/strings.xml
+++ b/apk/res/values-km/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"ទិន្នន័យនេះរួមបញ្ចូលព័ត៌មាន ដូចជាពេលវេលាសកម្ម ប្រភេទលំហាត់ប្រាណ ជុំ ការធ្វើឡើងវិញ វគ្គ ឬចំនួនបោះដៃហែលទឹក"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ទិន្នន័យនេះរួមបញ្ចូលព័ត៌មាន ដូចជាដំណាក់កាលគេង និងពេលគេង"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"មើលធាតុទាំងអស់"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"ផ្លាស់ប្ដូរ​"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"លុប​ទិន្នន័យនេះ"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"ចូលប្រើទិន្នន័យសុខភាពរបស់អ្នក"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ផ្លូវលំហាត់ប្រាណ"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"សរសេរ​ផ្លូវលំហាត់ប្រាណ"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"អានអំពីផ្លូវនៃលំហាត់ប្រាណ"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"អានផ្លូវហាត់ប្រាណទាំងអស់"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"ចម្ងាយ"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"ចម្ងាយ"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"អានចម្ងាយ"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"ចង្វាក់បេះដូងពេលសម្រាក"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"អានចង្វាក់បេះដូងពេលសម្រាក"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"សរសេរ​ចង្វាក់បេះដូងពេលសម្រាក"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"សីតុណ្ហភាពស្បែក"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"សីតុណ្ហភាពស្បែក"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"អានសីតុណ្ហភាពស្បែក"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"សរសេរសីតុណ្ហភាពស្បែក"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"អនុញ្ញាតឱ្យ “<xliff:g id="APP_NAME">%1$s</xliff:g>” អាន"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"អនុញ្ញាតឱ្យ “<xliff:g id="APP_NAME">%1$s</xliff:g>” សរសេរ"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"បោះបង់"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"កំពុងលុបទិន្នន័យ Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"កំពុងលុបទិន្នន័យ Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"ការលុបទិន្នន័យ"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"លុបធាតុទិន្នន័យ"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"លុបធាតុ"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"លុបធាតុទិន្នន័យ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"លុបធាតុ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"សរុប៖ <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 វ៉ាត់}other{# វ៉ាត់}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"ផ្លាស់ទី​ចុះ​ក្រោម"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ផ្លាស់ទីទៅខាង​លើបំផុត"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"ផ្លាស់ទី​ទៅ​ខាងក្រោម​បំផុត"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"ប៊ូតុងសម្រាប់ដក <xliff:g id="SELECTED_APP">%s</xliff:g> ចេញពីបញ្ជីអាទិភាព"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"ចុចពីរដង ហើយអូស ដើម្បីតម្រៀបឡើងវិញ"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"សម្បទា សុខុមាលភាព"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"ការអនុញ្ញាត"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, ទិន្នន័យសុខភាព, ប្រភេទទិន្នន័យ, សិទ្ធិចូលប្រើទិន្នន័យ, សកម្មភាព, រង្វាស់រាងកាយ, ការតាមដានវដ្តរដូវ, អាហារូបត្ថម្ភ, ដេក, សរីរាង្គសំខាន់ៗ"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"មានតែកម្មវិធីដែលអ្នកអនុញ្ញាតឱ្យចូលប្រើផ្លូវហាត់ប្រាណរបស់អ្នកប៉ុណ្ណោះ"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"តើខ្ញុំអាចគ្រប់គ្រងសិទ្ធិចូលប្រើតាមរបៀបណា?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"អ្នកអាចគ្រប់គ្រងសិទ្ធិរបស់កម្មវិធីក្នុងការចូលប្រើផ្លូវហាត់ប្រាណនៅក្នុងការកំណត់ Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"ថយក្រោយ"</string>
     <string name="loading" msgid="2526615755685950317">"កំពុងផ្ទុក…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"ការរួមបញ្ចូល​កំពុងដំណើរការ"</string>
diff --git a/apk/res/values-kn/strings.xml b/apk/res/values-kn/strings.xml
index 54d3645..20f69a0 100644
--- a/apk/res/values-kn/strings.xml
+++ b/apk/res/values-kn/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"ಈ ಡೇಟಾ, ಸಕ್ರಿಯವಾಗಿದ್ದ ಸಮಯ, ವ್ಯಾಯಾಮದ ಪ್ರಕಾರ, ಲ್ಯಾಪ್‌ಗಳು, ಪುನರಾವರ್ತನೆಗಳು, ಸೆಶನ್‌ಗಳು ಅಥವಾ ಈಜುವಿಕೆ ಸ್ಟ್ರೋಕ್‌ಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ಈ ಡೇಟಾ, ನಿದ್ರೆಯ ಹಂತಗಳು ಹಾಗೂ ನಿದ್ರೆಯ ಅವಧಿಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"ಎಲ್ಲಾ ನಮೂದುಗಳನ್ನು ನೋಡಿ"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"ಬದಲಾಯಿಸಿ"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"ಈ ಡೇಟಾವನ್ನು ಅಳಿಸಿ"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"ನಿಮ್ಮ ಹೆಲ್ತ್‌ ಡೇಟಾಗೆ ಆ್ಯಕ್ಸೆಸ್ ಪಡೆಯಿರಿ"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ವ್ಯಾಯಾಮದ ಯೋಜನೆ"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"ವ್ಯಾಯಾಮದ ಯೋಜನೆಯನ್ನು ಬರೆಯಿರಿ"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"ವ್ಯಾಯಾಮದ ಯೋಜನೆಯನ್ನು ಓದಿರಿ"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"ವ್ಯಾಯಾಮ ಮಾಡುವ ಎಲ್ಲಾ ವಿಧಾನಗಳನ್ನು ಓದಿ"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"ದೂರ"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"ದೂರ"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"ದೂರವನ್ನು ಓದುತ್ತದೆ"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"ವಿಶ್ರಾಂತ ಸ್ಥಿತಿಯಲ್ಲಿರುವ ಹೃದಯದ ಬಡಿತದ ಡೇಟಾ"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"ವಿಶ್ರಾಂತ ಸ್ಥಿತಿಯಲ್ಲಿರುವ ಹೃದಯದ ಬಡಿತದ ಡೇಟಾವನ್ನು ಓದುತ್ತದೆ"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"ವಿಶ್ರಾಂತ ಸ್ಥಿತಿಯಲ್ಲಿರುವ ಹೃದಯ ಬಡಿತದ ಡೇಟಾವನ್ನು ಬರೆಯುತ್ತದೆ"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"ಚರ್ಮದ ತಾಪಮಾನ"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"ಚರ್ಮದ ತಾಪಮಾನ"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"ಚರ್ಮದ ತಾಪಮಾನವನ್ನು ಓದಿ"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"ಚರ್ಮದ ತಾಪಮಾನವನ್ನು ಬರೆಯಿರಿ"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ಗೆ ಓದಲು ಅನುಮತಿಸಿ"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ಗೆ ಬರೆಯಲು ಅನುಮತಿಸಿ"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"ರದ್ದುಗೊಳಿಸಿ"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect ಡೇಟಾವನ್ನು ಅಳಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"ಡೇಟಾ ಅಳಿಸುವಿಕೆ"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"ಡೇಟಾ ನಮೂದನ್ನು ಅಳಿಸಿ"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"ನಮೂದನ್ನು ಅಳಿಸಿ"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ಡೇಟಾ ನಮೂದನ್ನು ಅಳಿಸಿ"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ನಮೂದನ್ನು ಅಳಿಸಿ"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"ಒಟ್ಟು: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ವ್ಯಾಟ್}one{# ವ್ಯಾಟ್‌ಗಳು}other{# ವ್ಯಾಟ್‌ಗಳು}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"ಕೆಳಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ಮೇಲಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"ಕೆಳಕ್ಕೆ ಸರಿಸಿ"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"ಆದ್ಯತೆಯ ಪಟ್ಟಿಯಿಂದ <xliff:g id="SELECTED_APP">%s</xliff:g> ಅನ್ನು ತೆಗೆದುಹಾಕಲು ಇರುವ ಬಟನ್"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"ಮರುಕ್ರಮಗೊಳಿಸಲು ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಹಾಗೂ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ಫಿಟ್‌ನೆಸ್, ಯೋಗಕ್ಷೇಮ"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"ಅನುಮತಿಗಳು"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, ಆರೋಗ್ಯದ ಡೇಟಾ, ಆರೋಗ್ಯದ ವರ್ಗಗಳು, ಡೇಟಾ ಆ್ಯಕ್ಸೆಸ್, ಚಟುವಟಿಕೆ, ದೇಹದ ಅಳತೆಗಳು, ಸೈಕಲ್ ಟ್ರ್ಯಾಕಿಂಗ್, ಪೌಷ್ಟಿಕತೆ, ನಿದ್ರೆ, ಆರೋಗ್ಯ ಮಾಪನಗಳು"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"ನೀವು ಅನುಮತಿಸುವ ಆ್ಯಪ್‌ಗಳು ಮಾತ್ರ ನಿಮ್ಮ ವ್ಯಾಯಾಮದ ಮಾರ್ಗಗಳನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಬಹುದು"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"ನಾನು ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ಹೇಗೆ ನಿರ್ವಹಿಸಬಹುದು?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"ನೀವು Health Connect ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ವ್ಯಾಯಾಮದ ಮಾರ್ಗಗಳಿಗೆ ಆ್ಯಪ್ ಆ್ಯಕ್ಸೆಸ್ ಅನ್ನು ನಿರ್ವಹಿಸಬಹುದು"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"ಹಿಂದಕ್ಕೆ"</string>
     <string name="loading" msgid="2526615755685950317">"ಲೋಡ್ ಆಗುತ್ತಿದೆ…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"ಇಂಟಿಗ್ರೇಶನ್ ಪ್ರಗತಿಯಲ್ಲಿದೆ"</string>
diff --git a/apk/res/values-ko/strings.xml b/apk/res/values-ko/strings.xml
index 4e2e3ad..f346dbd 100644
--- a/apk/res/values-ko/strings.xml
+++ b/apk/res/values-ko/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"이 데이터에는 활동 시간, 운동 종류, 랩, 반복, 세션 또는 수영 스트로크와 같은 정보가 포함됩니다."</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"이 데이터에는 수면 단계 및 수면 세션과 같은 정보가 포함됩니다."</string>
     <string name="all_entries_button" msgid="5109091107239135235">"모든 항목 보기"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"변경"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"데이터 삭제"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"헬스 커넥트"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"건강 데이터 액세스"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"운동 경로"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"운동 경로 기록"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"운동 루트 보기"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"모든 운동 경로 읽기"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"거리"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"거리"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"거리 읽기"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"안정시 심박수"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"안정시 심박수 읽기"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"안정시 심박수 쓰기"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"피부 온도"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"피부 온도"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"피부 온도 읽기"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"피부 온도 쓰기"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”에 읽기 권한 부여"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”에 쓰기 권한 부여"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"취소"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"헬스 커넥트 데이터 삭제"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"헬스 커넥트 데이터 삭제"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"데이터 삭제"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"데이터 항목 삭제"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"항목 삭제"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> 데이터 항목 삭제"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> 항목 삭제"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"총 <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1W}other{#W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1와트}other{#와트}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"아래로 이동"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"맨 위로 이동"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"맨 아래로 이동"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"우선순위 목록에서 <xliff:g id="SELECTED_APP">%s</xliff:g>을(를) 제거하는 버튼"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"두 번 탭한 후 드래그하여 순서 변경"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"피트니스, 웰니스"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"권한"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"헬스 커넥트, 건강 데이터, 건강 카테고리, 데이터 액세스, 활동, 신체 측정, 월경 주기 추적, 영양, 수면, 활력 징후"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"운동 경로에 액세스하도록 허용한 앱만 볼 수 있습니다."</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"어떻게 액세스를 관리하나요?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"헬스 커넥트 설정에서 운동 경로에 액세스하는 앱을 관리할 수 있습니다."</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"뒤로"</string>
     <string name="loading" msgid="2526615755685950317">"로드 중…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"통합 진행 중"</string>
diff --git a/apk/res/values-ky/strings.xml b/apk/res/values-ky/strings.xml
index 9e55c07..f7b8448 100644
--- a/apk/res/values-ky/strings.xml
+++ b/apk/res/values-ky/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Канча убакыт машыкканыңыз, кандай көнүгүүлөрдү жасаганыңыз, канча жолу айланып жана кайталаганыңыз, канча ирет жасаганыңыз же канча жолу чабак урганыңыз тууралуу маалымат"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Уйку тууралуу маалымат, анын фазалары сыяктуу"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Бардык киргизилген нерселерди көрүү"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"өзгөртүү"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Бул нерселерди өчүрүү"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"ден соолукка байланыштуу нерселерди көрүү мүмкүнчүлүгү"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"машыгуу маршруту"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Машыгуу маршрутун жазуу"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Машыгуу маршрутун окуу"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Бардык машыгуу маршруттарын окуу"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Аралык"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"аралык"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Аралыкты окуу"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"тынч абалдагы жүрөктүн согушу"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Тынч абалдагы жүрөктүн согушун окуу"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Тынч абалдагы жүрөктүн согушун жазуу"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Теринин температурасы"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"теринин температурасы"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Теринин температурасын окуу"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Теринин температурасын жазуу"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” колдонмосуна окууга уруксат берүү"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” колдонмосуна жазууга уруксат берүү"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Жок"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect кызматындагы нерселер өчүүдө"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect кызматындагы нерселер өчүүдө"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Өчүүдө"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Киргизилген нерселерди өчүрүү"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Киргизилген нерселерди өчүрүү"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Киргизилген нерселерди өчүрүү: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Киргизилген нерселерди өчүрүү: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Жалпысынан: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 Вт}other{# Вт}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ватт}other{# ватт}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Төмөн жылдыруу"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Башына жылдыруу"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Аягына жылдыруу"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"<xliff:g id="SELECTED_APP">%s</xliff:g> колдонмосун маанилүүлөр тизмесинен өчүрүү баскычы"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Иретин өзгөртүү үчүн эки жолу басып, сүйрөңүз"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"фитнес, саламаттык"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"уруксаттар"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, ден соолукка байланыштуу нерселер, ден соолук категориялары, маалыматка мүмкүнчүлүк алуу, кыймылдуулук, дене-бой өлчөмдөрү, циклге көз салуу, тамактануу, уйку, организмдин негизги көрсөткүчтөрү"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Кайда машыгып жүргөнүңүздү көрүүгө уруксат берген колдонмолор гана"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Кирүү мүмкүнчүлүгүн кантип тескей алам?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Колдонмолордун кайда машыгын жүргөнүңүздү көрүү мүмкүнчүлүгүн Health Connect параметрлеринен тескей аласыз"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Артка"</string>
     <string name="loading" msgid="2526615755685950317">"Жүктөлүүдө…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Интеграция аткарылууда"</string>
diff --git a/apk/res/values-lo/strings.xml b/apk/res/values-lo/strings.xml
index 6bc4351..9cc712f 100644
--- a/apk/res/values-lo/strings.xml
+++ b/apk/res/values-lo/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"ຂໍ້ມູນນີ້ຮວມມີຂໍ້ມູນຕ່າງໆ ເຊັ່ນ: ເວລາເຄື່ອນໄຫວຮ່າງກາຍ, ປະເພດການອອກກຳລັງກາຍ, ຈຳນວນຮອບ, ຈຳນວນເທື່ອທີ່ເຮັດຊ້ຳ, ເຊດຊັນ ຫຼື ສະໂຕຣກການລອຍນ້ຳ"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ຂໍ້ມູນນີ້ຮວມມີຂໍ້ມູນຕ່າງໆ ເຊັ່ນ: ໄລຍະການນອນຫຼັບ ແລະ ຊ່ວງເວລານອນຕ່າງໆ"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"ເບິ່ງລາຍການຂໍ້ມູນທັງໝົດ"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"ປ່ຽນ"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"ລຶບຂໍ້ມູນນີ້ອອກ"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"ເຂົ້າເຖິງຂໍ້ມູນສຸຂະພາບຂອງທ່ານ"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ເສັ້ນທາງອອກກຳລັງກາຍ"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"ຂຽນເສັ້ນທາງອອກກຳລັງກາຍ"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"ອ່ານເສັ້ນທາງອອກກຳລັງກາຍ"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"ອ່ານເສັ້ນທາງການອອກກຳລັງກາຍທັງໝົດ"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"ໄລຍະທາງ"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"ໄລຍະທາງ"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"ອ່ານຂໍ້ມູນໄລຍະທາງ"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"ອັດຕາການເຕັ້ນຫົວໃຈໃນເວລາພັກຜ່ອນ"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"ອ່ານຂໍ້ມູນອັດຕາການເຕັ້ນຫົວໃຈເວລາພັກຜ່ອນ"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"ຂຽນຂໍ້ມູນອັດຕາການເຕັ້ນຫົວໃຈໃນເວລາພັກຜ່ອນ"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"ອຸນຫະພູມຜິວໜັງ"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"ອຸນຫະພູມຜິວໜັງ"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"ອ່ານຂໍ້ມູນອຸນຫະພູມຜິວໜັງ"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"ຂຽນຂໍ້ມູນອຸນຫະພູມຜິວໜັງ"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"ອະນຸຍາດໃຫ້ “<xliff:g id="APP_NAME">%1$s</xliff:g>” ອ່ານ"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"ອະນຸຍາດໃຫ້ “<xliff:g id="APP_NAME">%1$s</xliff:g>” ຂຽນ"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"ຍົກເລີກ"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"ກຳລັງລຶບຂໍ້ມູນ Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"ກຳລັງລຶບຂໍ້ມູນ Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"ການລຶບຂໍ້ມູນ"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"ລຶບລາຍການຂໍ້ມູນ"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"ລຶບລາຍການຂໍ້ມູນ"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"ລຶບລາຍການຂໍ້ມູນ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"ລຶບລາຍການ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"ທັງໝົດ: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ວັດ}other{# ວັດ}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"ຍ້າຍລົງ"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ຍ້າຍໄປເທິງສຸດ"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"ຍ້າຍໄປລຸ່ມສຸດ"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"ປຸ່ມສຳລັບລຶບ <xliff:g id="SELECTED_APP">%s</xliff:g> ອອກຈາກລາຍຊື່ສຳຄັນ"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"ແຕະສອງເທື່ອແລ້ວລາກເພື່ອຈັດຮຽງຄືນໃໝ່"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ການອອກກຳລັງກາຍ, ສຸຂະພາບ"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"ການອະນຸຍາດ"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, ຂໍ້ມູນສຸຂະພາບ, ໝວດໝູ່ສຸຂະພາບ, ສິດເຂົ້າເຖິງຂໍ້ມູນ, ການເຄື່ອນໄຫວ, ການວັດແທກຮ່າງກາຍ, ການຕິດຕາມຮອບວຽນ, ໂພຊະນາການ, ການນອນ, ສັນຍານຊີບ"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"ມີແຕ່ແອັບທີ່ທ່ານອະນຸຍາດໃຫ້ເຂົ້າເຖິງເສັ້ນທາງອອກກຳລັງກາຍຂອງທ່ານເທົ່ານັ້ນ"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"ຂ້ອຍສາມາດຈັດການສິດເຂົ້າເຖິງໄດ້ແນວໃດ?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"ທ່ານສາມາດຈັດການສິດເຂົ້າເຖິງເສັ້ນທາງການອອກກຳລັງກາຍຂອງແອັບໄດ້ໃນການຕັ້ງຄ່າ Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"ກັບຄືນ"</string>
     <string name="loading" msgid="2526615755685950317">"ກຳລັງໂຫຼດ…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"ກຳລັງດຳເນີນການເຊື່ອມໂຍງ"</string>
diff --git a/apk/res/values-lt/strings.xml b/apk/res/values-lt/strings.xml
index 99f5827..ceb5ef3 100644
--- a/apk/res/values-lt/strings.xml
+++ b/apk/res/values-lt/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Į šiuos duomenis įtraukiama informacija, pvz., aktyvumo laikas, pratimo tipas, ratai, pakartojimai, seansai ar plaukimo mostai"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Į šiuos duomenis įtraukiama informacija, pvz., miego fazės ir miego seansai"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Žr. visus įrašus"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"pakeisti"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Ištrinti šiuos duomenis"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"prieiga prie sveikatos duomenų"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"mankštos maršrutas"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Rašyti mankštos maršrutą"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Skaityti mankštos maršrutą"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Skaityti visus mankštos maršrutus"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Atstumas"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"atstumas"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Skaityti atstumo duomenis"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"pulso dažnis ilsintis"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Skaityti pulso dažnio ilsintis duomenis"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Rašyti pulso dažnio ilsintis duomenis"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Odos temperatūra"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"odos temperatūra"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Nuskaityti odos temperatūrą"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Įrašyti odos temperatūrą"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Leidimas „<xliff:g id="APP_NAME">%1$s</xliff:g>“ skaityti"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Leidimas „<xliff:g id="APP_NAME">%1$s</xliff:g>“ rašyti"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Atšaukti"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Ištrinami „Health Connect“ duomenys"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Ištrinami „Health Connect“ duomenys"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Duomenų ištrynimas"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Ištrinti duomenų įrašą"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Ištrinti įrašą"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Ištrinti duomenų įrašą <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Ištrinti įrašą <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Iš viso: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}few{# W}many{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vatas}one{# vatas}few{# vatai}many{# vato}other{# vatų}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Perkelti žemyn"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Perkelti į viršų"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Perkelti į apačią"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Mygtukas, pašalinantis „<xliff:g id="SELECTED_APP">%s</xliff:g>“ iš prioritetų sąrašo"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Dukart palieskite ir vilkite, kad pertvarkytumėte"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"mankšta, sveikatingumas"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"leidimai"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, sveikatos duomenys, sveikatos duomenų kategorijos, prieiga prie duomenų, veikla, kūno matavimai, ciklo stebėjimas, mityba, miegas, gyvybinių funkcijų rodikliai"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Tik programos, kurioms leidžiate pasiekti mankštos maršrutus"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Kaip galiu valdyti programų prieigą?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Programų prieigą prie mankštos maršrutų galite valdyti „Health Connect“ nustatymuose"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Atgal"</string>
     <string name="loading" msgid="2526615755685950317">"Įkeliama…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Vyksta integravimas"</string>
diff --git a/apk/res/values-lv/strings.xml b/apk/res/values-lv/strings.xml
index 50a50b9..427f494 100644
--- a/apk/res/values-lv/strings.xml
+++ b/apk/res/values-lv/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Šie dati ietver tādu informāciju kā aktivitātes ilgums, treniņa veids, apļu skaits, atkārtojumi, sesijas vai peldēšanas vēzieni."</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Šie dati ietver tādu informāciju kā miega fāzes un miega sesijas."</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Skatīt visus ierakstus"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"mainīt"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Dzēst šos datus"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"piekļuve jūsu veselības rādītāju datiem"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"fizisko aktivitāšu maršruts"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Ierakstīt fizisko aktivitāšu maršrutu"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Lasīt fizisko aktivitāšu maršruta datus"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Lasīt visus treniņu maršrutus"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Attālums"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"attālums"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Lasīt attāluma datus"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"sirdsdarbības ātrums miera stāvoklī"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Lasīt sirdsdarbības ātrumu miera stāvoklī"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Rakstīt sirdsdarbības ātrumu miera stāvoklī"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Ādas temperatūra"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"ādas temperatūra"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Lasīt ādas temperatūru"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Rakstīt ādas temperatūru"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Atļauja lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> lasīt datus"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Atļauja lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g> rakstīt datus"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Atcelt"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Notiek Health Connect datu dzēšana"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Notiek Health Connect datu dzēšana"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Datu dzēšana"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Dzēst datu ierakstu"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Dzēst ierakstu"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Dzēst datu ierakstu: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Dzēst ierakstu: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Kopā: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}zero{# W}one{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vats}zero{# vatu}one{# vats}other{# vati}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Pārvietot uz leju"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Pārvietot uz sākumu"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Pārvietot uz beigām"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Poga lietotnes <xliff:g id="SELECTED_APP">%s</xliff:g> noņemšanai no prioritāšu saraksta"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Veikt dubultskārienu un vilkt, lai pārvietotu"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fiziskā sagatavotība, labsajūta"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"atļaujas"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, veselības dati, veselības kategorijas, piekļuve datiem, aktivitātes, ķermeņa rādītāji, cikla uzskaite, uzturs, miegs, veselības rādījumi"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Tikai lietotnes, kurām esat sniedzis piekļuvi jūsu treniņu maršrutiem"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Kā varu pārvaldīt piekļuvi?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Varat pārvaldīt lietotņu piekļuvi treniņu maršrutiem platformas Health Connect iestatījumos"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Atpakaļ"</string>
     <string name="loading" msgid="2526615755685950317">"Notiek ielāde…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Notiek integrēšana"</string>
diff --git a/apk/res/values-mk/strings.xml b/apk/res/values-mk/strings.xml
index 9eb72bc..d956a23 100644
--- a/apk/res/values-mk/strings.xml
+++ b/apk/res/values-mk/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Податоциве вклучуваат информации како активно време, тип на вежба, кругови, серии, сесии или потези на пливање"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Податоциве вклучуваат информации како фази и сесии на спиење"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Видете ги сите записи"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"променување"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Избришете ги податоците"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"пристапување до податоците за здравјето"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"маршрута на вежбање"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Запиши маршрута на вежбање"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Читај ја маршрутата на вежбање"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Читање на сите маршрути за вежбање"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Растојание"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"растојание"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Читање растојание"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"пулс во мирување"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Читање пулс во мирување"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Запишување пулс во мирување"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Температура на кожата"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"температура на кожата"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Читање на температурата на кожата"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Запишување на температурата на кожата"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Дозволете „<xliff:g id="APP_NAME">%1$s</xliff:g>“ да чита"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Дозволете „<xliff:g id="APP_NAME">%1$s</xliff:g>“ да пишува"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Откажи"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Се бришат податоците на Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Се бришат податоците на Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Бришење податоци"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Бришење внес на податоци"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Избриши го записот"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Бришење внес на податоци <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Избриши го внесот на податоци <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Вкупно: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ват}one{# ват}other{# вати}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Премести надолу"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Премести најгоре"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Премести најдолу"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Копче за отстранување на <xliff:g id="SELECTED_APP">%s</xliff:g> од приоритетната листа"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Допрете двапати и повлечете за да прераспоредите"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"фитнес, велнес"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"дозволи"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, податоци за здравјето, здравствени категории, пристап до податоци, активност, телесни мерења, следење на циклусот, исхрана, спиење, витални функции"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Само апликациите на кои им дозволувате пристап до вашите маршрути за вежбање"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Како да управувам со пристапот?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Може да управувате со пристапот на апликацијата до маршрутите за вежбање во поставките на Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Назад"</string>
     <string name="loading" msgid="2526615755685950317">"Се вчитува…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Интеграцијата е во тек"</string>
diff --git a/apk/res/values-ml/strings.xml b/apk/res/values-ml/strings.xml
index 0973b18..8d53244 100644
--- a/apk/res/values-ml/strings.xml
+++ b/apk/res/values-ml/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"സജീവമായ സമയം, വ്യായാമ തരം, ലാപ്പുകൾ, ആവർത്തനങ്ങൾ, സെഷനുകൾ, നീന്തൽ സ്‌ട്രോക്കുകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ ഈ ഡാറ്റയിൽ ഉൾപ്പെടുന്നു"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ഉറക്ക ഘട്ടങ്ങൾ, ഉറക്ക സെഷനുകൾ എന്നിവ പോലുള്ള വിവരങ്ങൾ ഈ ഡാറ്റയിൽ ഉൾപ്പെടുന്നു"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"എല്ലാ എൻട്രികളും കാണുക"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"മാറ്റുക"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"ഈ ഡാറ്റ ഇല്ലാതാക്കുക"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"നിങ്ങളുടെ ആരോഗ്യ ഡാറ്റ ആക്സസ് ചെയ്യുക"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"വ്യായാമ റൂട്ട്"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"വ്യായാമ റൂട്ട് റൈറ്റ് ചെയ്യുക"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"വ്യായാമ റൂട്ട് റീഡ് ചെയ്യുക"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"വ്യായാമ സെഷന്റെ വഴികൾ"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"ദൂരം"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"ദൂരം"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"ദൂരം റീഡ് ചെയ്യുക"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"വിശ്രമ സമയത്തെ ഹൃദയമിടിപ്പ്"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"വിശ്രമ സമയത്തെ ഹൃദയമിടിപ്പ് സംബന്ധിച്ച ഡാറ്റ റീഡ് ചെയ്യുക"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"വിശ്രമ സമയത്തെ ഹൃദയമിടിപ്പ് സംബന്ധിച്ച ഡാറ്റ റൈറ്റ് ചെയ്യുക"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"ചർമ്മത്തിലെ താപനില"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"ചർമ്മത്തിലെ താപനില"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"ചർമ്മത്തിലെ താപനില വായിക്കുക"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"ചർമ്മത്തിലെ താപനില എഴുതുക"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"റീഡ് ചെയ്യാൻ “<xliff:g id="APP_NAME">%1$s</xliff:g>” ആപ്പിനെ അനുവദിക്കുക"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"റൈറ്റ് ചെയ്യാൻ “<xliff:g id="APP_NAME">%1$s</xliff:g>” ആപ്പിനെ അനുവദിക്കുക"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"റദ്ദാക്കുക"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect ഡാറ്റ ഇല്ലാതാക്കുന്നു"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect ഡാറ്റ ഇല്ലാതാക്കുന്നു"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"ഡാറ്റ ഇല്ലാതാക്കൽ"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"ഡാറ്റാ എൻട്രി ഇല്ലാതാക്കുക"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"എൻട്രി ഇല്ലാതാക്കുക"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ഡാറ്റാ എൻട്രി ഇല്ലാതാക്കുക"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> എൻട്രി ഇല്ലാതാക്കുക"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"ആകെ: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{ഒരു വാട്ട്}other{# വാട്ട്}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"താഴേക്ക് നീക്കുക"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ഏറ്റവും മുകളിലേക്ക് നീക്കുക"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"ഏറ്റവും താഴേക്ക് നീക്കുക"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"മുൻഗണനാ ലിസ്റ്റിൽ നിന്ന് <xliff:g id="SELECTED_APP">%s</xliff:g> നീക്കം ചെയ്യാനുള്ള ബട്ടൺ"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"പുനഃക്രമീകരിക്കാൻ ഡബിൾ ടാപ്പ് ചെയ്‌ത് വലിച്ചിടുക"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ഫിറ്റ്‌നസ്, ആരോഗ്യം"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"അനുമതികൾ"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, ആരോഗ്യ ഡാറ്റ, ആരോഗ്യ വിഭാഗങ്ങൾ, ഡാറ്റാ ആക്‌സസ്, ആക്റ്റിവിറ്റി, ശാരീരിക അളവുകൾ, സൈക്കിൾ ട്രാക്കിംഗ്, പോഷകാഹാരം, ഉറക്കം, പ്രധാന ആരോഗ്യ വിവരങ്ങൾ"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"വ്യായാമ സെഷന്റെ വഴികൾ ആക്‌സസ് ചെയ്യാൻ നിങ്ങൾ അനുവദിച്ചിട്ടുള്ള ആപ്പുകൾക്ക് മാത്രം"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"എനിക്ക് എങ്ങനെ ആക്‌സസ് മാനേജ് ചെയ്യാനാകും?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"നിങ്ങൾക്ക് വ്യായാമ സെഷന്റെ വഴികളിലേക്കുള്ള ആപ്പ് ആക്‌സസ് Health Connect ക്രമീകരണത്തിൽ മാനേജ് ചെയ്യാം"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"മടങ്ങുക"</string>
     <string name="loading" msgid="2526615755685950317">"ലോഡ് ചെയ്യുന്നു…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"സംയോജനം പുരോഗമിക്കുന്നു"</string>
diff --git a/apk/res/values-mn/strings.xml b/apk/res/values-mn/strings.xml
index 9c86cc5..0c4f866 100644
--- a/apk/res/values-mn/strings.xml
+++ b/apk/res/values-mn/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Энэ өгөгдөлд идэвхтэй хугацаа, дасгалын төрөл, тойрог, давталт, дасгалын хугацаа эсвэл сэлэлтийн төрөл гэх мэт мэдээлэл багтана"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Энэ өгөгдөлд нойрны үе шатууд болон унтах хугацаа зэрэг мэдээлэл багтана"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Бүх оруулгыг харах"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"өөрчлөх"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Энэ өгөгдлийг устгах"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"таны эрүүл мэндийн өгөгдөлд хандах"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"дасгалын маршрут"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Дасгалын маршрут бичих"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Дасгалын маршрутыг уншина уу"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Дасгалын бүх маршрутыг унших"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Зай"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"зай"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Зайг унших"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"амарч буй үеийн зүрхний хэм"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Амарч буй үеийн зүрхний хэмийг унших"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Амарч буй үеийн зүрхний хэмийг бичих"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Арьсны температур"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"арьсны температур"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Арьсны температурыг унших"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Арьсны температурыг бичих"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” г уншихыг зөвшөөрөх"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” г бичихийг зөвшөөрөх"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Цуцлах"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect-н өгөгдлийг устгаж байна"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect-н өгөгдлийг устгаж байна"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Өгөгдөл устгах"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Өгөгдлийн оролтыг устгах"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Оруулгыг устгах"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>-н өгөгдлийн оролтыг устгана уу"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>-н оролтыг устгах"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Нийт: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 Вт}other{# Вт}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ватт}other{# ватт}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Доош зөөх"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Дээд тал руу зөөх"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Доод тал руу зөөх"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"<xliff:g id="SELECTED_APP">%s</xliff:g>-г чухал зүйлсийн жагсаалтаас хасах товч"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Дахин эрэмбэлэхийн тулд хоёр товшоод чирнэ үү"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"фитнес, эрүүл аж төрөх ёс"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"зөвшөөрөл"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, эрүүл мэндийн өгөгдөл, эрүүл мэндийн ангилал, өгөгдлийн хандалт, үйл ажиллагаа, биеийн хэмжээ, мөчлөгийн хяналт, тэжээллэг чанар, унтлага, үзүүлэлт"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Таны зөвхөн дасгалын маршрутад хандахыг зөвшөөрсөн аппууд"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Би хандалтыг хэрхэн удирдаж болох вэ?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Та Health Connect-н тохиргоонд дасгалын маршрутын аппын хандалтыг удирдах боломжтой"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Буцах"</string>
     <string name="loading" msgid="2526615755685950317">"Ачаалж байна…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Нэгтгэж байна"</string>
diff --git a/apk/res/values-mr/strings.xml b/apk/res/values-mr/strings.xml
index 9b5eb11..953eab5 100644
--- a/apk/res/values-mr/strings.xml
+++ b/apk/res/values-mr/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"या डेटामध्ये अ‍ॅक्टिव्ह वेळ, व्यायामाचा प्रकार, लॅप, पुनरावृत्ती, सेशन किंवा स्विमिंग स्‍ट्रोक यांसारख्या माहितीचा समावेश आहे"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"या डेटामध्ये झोपेचे टप्पे आणि झोपेची सेशन यांसारख्या माहितीचा समावेश आहे"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"सर्व एंट्री पहा"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"बदला"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"हा डेटा हटवा"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"तुमच्या आरोग्याशी संबंधित डेटा अ‍ॅक्सेस करा"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"व्यायामाचा मार्ग"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"व्यायामाचा मार्ग लिहा"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"व्यायामाशी संबंधित मार्ग रीड करा"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"व्यायामाचे सर्व मार्ग वाचा"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"अंतराशी संबंधित डेटा"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"अंतराशी संबंधित डेटा"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"अंतराशी संबंधित डेटा रीड करा"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"आराम करतानाच्या हार्ट रेटशी संबंधित डेटा"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"आराम करतानाच्या हार्ट रेटशी संबंधित डेटा रीड करा"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"आराम करतानाच्या हार्ट रेटशी संबंधित डेटा राइट करा"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"त्वचेचे तापमान"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"त्वचेचे तापमान"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"त्वचेचे तापमान वाचा"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"त्वचेचे तापमान लिहा"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ला रीड करण्याची अनुमती द्या"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” राइट करण्याची अनुमती द्या"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"रद्द करा"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect मधील डेटा हटवत आहे"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect मधील डेटा हटवत आहे"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"डेटा हटवणे"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"डेटाशी संबंधित नोंदी हटवा"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"एंट्री हटवा"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> डेटाची एंट्री हटवा"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> एंट्री हटवा"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"एकूण: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{एक वॅट}other{# वॅट}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{एक वॅट}other{# वॅट}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"खाली हलवा"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"सर्वात वरती हलवा"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"तळाशी हलवा"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"प्राधान्य सूचीमधून <xliff:g id="SELECTED_APP">%s</xliff:g> काढून टाकण्यासाठीचे बटण"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"परत क्रमाने लावण्यासाठी दोनदा टॅप करून ड्रॅग करा"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"फिटनेस, स्वास्थ्य"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"परवानग्या"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, आरोग्याशी संबंधित डेटा, आरोग्याशी संबंधित वर्गवाऱ्या, डेटा अ‍ॅक्सेस, अ‍ॅक्टिव्हिटी, शरीराचे मोजमाप, मासिक पाळीचा माग ठेवणे, पोषण, झोप, परिमाणे"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"फक्त तुम्ही तुमच्या व्यायामाचे मार्ग अ‍ॅक्सेस करण्याची अनुमती दिलेली अ‍ॅप्स"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"मला अ‍ॅक्सेस कसा व्यवस्थापित करता येईल?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"तुम्ही Health Connect सेटिंग्जमध्ये व्यायामाच्या मार्गांसाठी अ‍ॅप अ‍ॅक्सेस व्यवस्थापित करू शकता"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"मागे जा"</string>
     <string name="loading" msgid="2526615755685950317">"लोड करत आहे…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"इंटिग्रेशन प्रगतीपथावर आहे"</string>
diff --git a/apk/res/values-ms/strings.xml b/apk/res/values-ms/strings.xml
index 8ec9dcb..d6f246b 100644
--- a/apk/res/values-ms/strings.xml
+++ b/apk/res/values-ms/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Data ini mengandungi maklumat seperti masa aktif, jenis senaman, pusingan, ulangan, sesi atau kuak renang."</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Data ini mengandungi maklumat seperti peringkat tidur dan sesi tidur."</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Lihat semua entri"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"tukar"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Padamkan data ini"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"akses data kesihatan anda"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"laluan senaman"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Tulis laluan senaman"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Baca laluan senaman"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Baca semua laluan senaman"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Jarak"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"jarak"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Baca jarak"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"kadar denyut jantung rehat"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Baca kadar denyut jantung rehat"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Tulis kadar denyut jantung rehat"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Suhu kulit"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"suhu kulit"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Baca suhu kulit"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Tulis suhu kulit"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Benarkan “<xliff:g id="APP_NAME">%1$s</xliff:g>” membaca"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Benarkan “<xliff:g id="APP_NAME">%1$s</xliff:g>” menulis"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Batal"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Memadamkan data Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Memadamkan data Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Pemadaman data"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Padamkan masukan data"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Padam entri"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Padamkan masukan data <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Padamkan masukan <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Jumlah: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Alih ke bawah"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Alih ke atas sekali"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Alih ke bawah sekali"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Butang mengalih keluar <xliff:g id="SELECTED_APP">%s</xliff:g> daripada senarai keutamaan"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Ketik dua kali dan seret untuk menyusun semula apl"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"kecergasan, kesihatan"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"kebenaran"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, data kesihatan, kategori kesihatan, akses data, aktiviti, ukuran badan, penjejakan kitaran, pemakanan, tidur, vital"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Hanya apl yang anda benarkan untuk mengakses laluan senaman anda"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Bagaimanakah saya boleh mengurus akses?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Anda boleh mengurus akses apl kepada laluan senaman dalam tetapan Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Kembali"</string>
     <string name="loading" msgid="2526615755685950317">"Memuatkan…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Penyepaduan dalam proses"</string>
diff --git a/apk/res/values-my/strings.xml b/apk/res/values-my/strings.xml
index 55ca736..25ba4c3 100644
--- a/apk/res/values-my/strings.xml
+++ b/apk/res/values-my/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"ဤဒေတာတွင် လှုပ်ရှားချိန်၊ လေ့ကျင့်ခန်းအမျိုးအစား၊ အကြိမ်ရေ၊ အကျော့ရေ၊ စက်ရှင် (သို့) ရေကူးခပ်သည့် အရေအတွက်များကဲ့သို့ အချက်အလက်များပါဝင်သည်"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ဤဒေတာတွင် အိပ်စက်မှုဆိုင်ရာ အဆင့်နှင့် စက်ရှင်များကဲ့သို့ အချက်အလက်များပါဝင်သည်"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"ထည့်သွင်းမှုအားလုံးကြည့်ရန်"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"ပြောင်းလဲရန်"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"ဤဒေတာကို ဖျက်ရန်"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"ကျန်းမာရေးဒေတာကို သုံးနိုင်သည်"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"လေ့ကျင့်ခန်း လမ်းကြောင်း"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"လေ့ကျင့်ခန်းလမ်းကြောင်း ရေးရန်"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"လေ့ကျင့်ခန်း ပုံမှန်အစီအစဉ် ဖတ်ရန်"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"လေ့ကျင့်ခန်းလမ်းကြောင်းများအားလုံး ဖတ်နိုင်သည်"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"အကွာအဝေး"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"အကွာအဝေး"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"အကွာအဝေးကို ဖတ်ရန်"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"နားနေချိန် နှလုံးခုန်နှုန်း"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"နားနေချိန် နှလုံးခုန်နှုန်းကို ဖတ်ရန်"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"နားနေချိန် နှလုံးခုန်နှုန်းကို ရေးရန်"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"အရေပြားအပူချိန်"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"အရေပြားအပူချိန်"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"အရေပြားအပူချိန် ဖတ်ရန်"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"အရေပြားအပူချိန် ရေးရန်"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ကို ဖတ်ခွင့်ပြုခြင်း"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ကို ရေးခွင့်ပြုခြင်း"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"မလုပ်တော့"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect ဒေတာ ဖျက်နေသည်"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect ဒေတာ ဖျက်နေသည်"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"ဒေတာဖျက်ခြင်း"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"ဒေတာထည့်သွင်းမှု ဖျက်ရန်"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"ထည့်သွင်းမှု ဖျက်ရန်"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"ဒေတာထည့်သွင်းမှု <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ဖျက်ရန်"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"ထည့်သွင်းမှု <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ဖျက်ရန်"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"စုစုပေါင်း- <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{၁ W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{၁ ဝပ်}other{# ဝပ်}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"အောက်ရွှေ့ရန်"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ထိပ်ပိုင်းသို့ ရွှေ့ရန်"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"အောက်ခြေသို့ ရွှေ့ရန်"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"<xliff:g id="SELECTED_APP">%s</xliff:g> ကို ဦးစားပေးစာရင်းမှ ဖယ်ရှားရန် ခလုတ်"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"ပြန်စီရန် နှစ်ချက်တို့ပြီး ဖိဆွဲပါ"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ကျန်းမာကြံ့ခိုင်ရေး၊ ကြံ့ခိုင်မှု"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"ခွင့်ပြုချက်များ"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect၊ ကျန်းမာရေးဒေတာ၊ ကျန်းမာရေး အမျိုးအစားများ၊ ဒေတာသုံးခွင့်၊ လှုပ်ရှားမှု၊ ခန္ဓာကိုယ် တိုင်းတာချက်များ၊ ရာသီစက်ဝန်းခြေရာခံခြင်း၊ အာဟာရ၊ အိပ်စက်မှု၊ အဓိကကိုယ်တွင်းအင်္ဂါအခြေအနေ"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"သင်ခွင့်ပြုသော အက်ပ်များကသာ လေ့ကျင့်ခန်းလမ်းကြောင်းများကို သုံးနိုင်သည်"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"သုံးခွင့်ကို ဘယ်လိုစီမံနိုင်သလဲ။"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"လေ့ကျင့်ခန်းလမ်းကြောင်းများအတွက် အက်ပ်သုံးခွင့်ကို Health Connect ဆက်တင်များတွင် စီမံနိုင်သည်"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"နောက်သို့"</string>
     <string name="loading" msgid="2526615755685950317">"ဖွင့်နေသည်…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"ပေါင်းစည်းနေဆဲဖြစ်သည်"</string>
diff --git a/apk/res/values-nb/strings.xml b/apk/res/values-nb/strings.xml
index 2373c9d..7301bc0 100644
--- a/apk/res/values-nb/strings.xml
+++ b/apk/res/values-nb/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Disse dataene inkluderer informasjon som aktivitetstid, treningstype, runder, repetisjoner, økter eller svømmetak"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Disse dataene inkluderer informasjon som søvnstadier og søvnøkter"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Se alle oppføringer"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"bytt"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Slett disse dataene"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"bruke helsedataene dine"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"treningsrute"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Skriving av treningsruten"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Les treningsruten"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Les alle treningsruter"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distanse"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distanse"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Les distanse"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"hvilepuls"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Les hvilepuls"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Skriv hvilepuls"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Hudtemperatur"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"hudtemperatur"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Les hudtemperatur"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Skriv hudtemperatur"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"La «<xliff:g id="APP_NAME">%1$s</xliff:g>» lese"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"La «<xliff:g id="APP_NAME">%1$s</xliff:g>» skrive"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Avbryt"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Sletter Health Connect-data"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Sletter Health Connect-data"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Sletting av data"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Slett dataoppføringen"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Slett oppføringen"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Slett dataoppføringen <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Slett oppføringen <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Totalt: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Flytt ned"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Flytt til toppen"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Flytt til bunnen"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Knapp for å fjerne <xliff:g id="SELECTED_APP">%s</xliff:g> fra prioritetslisten"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Dobbelttrykk og dra for å endre rekkefølgen"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"trening, velvære"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"tillatelser"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, helsedata, helsekategorier, datatilgang, aktivitet, kroppsmålinger, syklussporing, ernæring, søvn, vitale tegn"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Bare apper du gir tilgang til treningsrutene dine"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Hvordan kan jeg administrere tilgangen?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Du kan administrere tilgangen apper har til treningsruter, i Health Connect-innstillingene"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Tilbake"</string>
     <string name="loading" msgid="2526615755685950317">"Laster inn …"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integreringen pågår"</string>
diff --git a/apk/res/values-ne/strings.xml b/apk/res/values-ne/strings.xml
index 1d1d432..64a3325 100644
--- a/apk/res/values-ne/strings.xml
+++ b/apk/res/values-ne/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"यस डेटामा शारीरिक क्रियाकलापको अवधि, कसरतको प्रकार, पूरा गरिएको ल्यापको सङ्ख्या, दोहोर्‍याएर गरिएका कसरतहरूको सङ्ख्या, सत्रहरूको सङ्ख्या वा पौडी खेल्ने शैली जस्ता जानकारी समावेश गरिन्छ"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"यस डेटामा निद्राका चरण र निद्राका सत्र जस्ता जानकारी समावेश गरिन्छ"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"सबै इन्ट्रीहरू हेर्नुहोस्"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"परिवर्तन गर्नुहोस्"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"यो डेटा मेटाउनुहोस्"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"आफ्नो स्वास्थ्यसम्बन्धी डेटा हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"कसरत गर्न जाने मार्ग"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"कसरत गर्न जाने मार्ग राइट गर्नुहोस्"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"कसरत गर्ने मार्गका बारेमा जानकारी रिड गरियोस्"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"तपाईंले कसरत गर्ने सबै मार्गहरू रिड गर्ने अनुमति दिनुहोस्"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"दूरी"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"दूरी"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"दूरीसम्बन्धी डेटा रिड गर्ने अनुमति दिनुहोस्"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"विश्राम गरेका बेलाको हृदयको गति"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"विश्राम गरेका बेलाको हृदयको गतिसम्बन्धी डेटा रिड गर्ने अनुमति दिनुहोस्"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"विश्राम गरेका बेलाको हृदयको गतिसम्बन्धी डेटा राइट गर्ने अनुमति दिनुहोस्"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"छालाको तापक्रम"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"छालाको तापक्रम"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"छालाको तापक्रमसम्बन्धी जानकारी रिड गर्ने"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"छालाको तापक्रमसम्बन्धी जानकारी राइट गर्ने"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” लाई रिड गर्ने अनुमति दिनुहोस्"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” लाई राइट गर्ने अनुमति दिनुहोस्"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"रद्द गर्नुहोस्"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect सम्बन्धी डेटा मेटाइँदै छ"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect सम्बन्धी डेटा मेटाइँदै छ"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"डेटा मेटाउने कार्य"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"डेटा इन्ट्री मेटाउनुहोस्"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"हालेको डेटा मेटाइयोस्"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> डेटा इन्ट्री मेटाउनुहोस्"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> इन्ट्री मेटाइयोस्"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"कुल: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{१ वाट}other{# वाट}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{१ वाट}other{# वाट}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"तल सार्नुहोस्"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"सारेर सिरानमा लैजानुहोस्"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"सारेर पुछारमा लैजानुहोस्"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"प्राथमिकता सूचीबाट <xliff:g id="SELECTED_APP">%s</xliff:g> हटाउने बटन"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"फेरि क्रमबद्ध गर्न डबल ट्याप गरी ड्र्याग गर्नुहोस्"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"फिटनेस, तन्दुरुस्ती"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"अनुमतिहरू"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, स्वास्थ्यसम्बन्धी डेटा, स्वास्थ्यका कोटी, डेटा प्रयोग गर्ने अनुमति, गतिविधि, शारीरिक नाप, महिनावारीको रेकर्ड राख्ने सुविधा, पोषण, निद्रा, स्वास्थ्यसम्बन्धी आधारभूत विवरण"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"तपाईंले कसरतका मार्गहरू हेर्ने अनुमति दिएका एपहरूले मात्र यो जानकारी हेर्न सक्छन्"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"एपलाई दिइएका अनुमति कसरी व्यवस्थापन गर्न सकिन्छ?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"तपाईं Health Connect का सेटिङमा गई एपलाई कसरत गर्ने मार्गहरू हेर्न दिइएको अनुमति व्यवस्थापन गर्न सक्नुहुन्छ"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"पछाडि"</string>
     <string name="loading" msgid="2526615755685950317">"लोड गरिँदै छ…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"इन्टिग्रेट गरिँदै छ"</string>
diff --git a/apk/res/values-nl/strings.xml b/apk/res/values-nl/strings.xml
index 113b8a1..ed6d43c 100644
--- a/apk/res/values-nl/strings.xml
+++ b/apk/res/values-nl/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Deze gegevens omvatten informatie zoals tijd actief, type beweging, ronden, herhalingen, sessies of zwemslagen"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Deze gegevens omvatten informatie zoals slaapfasen en slaapsessies"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Alle vermeldingen bekijken"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"wijzigen"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Deze gegevens verwijderen"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"je gezondheidsgegevens openen"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"trainingsroute"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Trainingsroute schrijven"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Trainingsroute lezen"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Alle trainingsroutes lezen"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Afstand"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"afstand"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Gegevens over afstand lezen"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"hartslag in rust"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Gegevens over hartslag in rust lezen"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Gegevens over hartslag in rust schrijven"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Huidtemperatuur"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"huidtemperatuur"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Huidtemperatuur lezen"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Huidtemperatuur schrijven"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"<xliff:g id="APP_NAME">%1$s</xliff:g> toestaan te lezen"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"<xliff:g id="APP_NAME">%1$s</xliff:g> toestaan te schrijven"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Annuleren"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect-gegevens verwijderen"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect-gegevens verwijderen"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Gegevensverwijdering"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Gegevensinvoer verwijderen"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Item verwijderen"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Gegevensinvoer <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> verwijderen"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Invoer <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> verwijderen"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Totaal: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Omlaag verplaatsen"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Bovenaan zetten"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Onderaan zetten"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Knop om <xliff:g id="SELECTED_APP">%s</xliff:g> uit prioriteitslijst te verwijderen"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Dubbeltik en sleep om de volgorde te wijzigen"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, welzijn"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"rechten"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, gezondheidsgegevens, gezondheidscategorieën, gegevenstoegang, activiteit, lichaamsmetingen, cyclus bijhouden, voeding, slaap, vitale functies"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Alleen apps die je toegang geeft tot je trainingsroutes"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Hoe kan ik de toegang beheren?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Je kunt de toegang van apps tot trainingsroutes beheren in de Health Connect-instellingen"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Terug"</string>
     <string name="loading" msgid="2526615755685950317">"Laden…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integratie is bezig"</string>
diff --git a/apk/res/values-or/strings.xml b/apk/res/values-or/strings.xml
index f08d662..4e5657f 100644
--- a/apk/res/values-or/strings.xml
+++ b/apk/res/values-or/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"ଏହି ଡାଟାରେ ସକ୍ରିୟ ସମୟ, ବ୍ୟାୟାମର ପ୍ରକାର, ଲାପ, ରିପିଟିସନ, ସେସନ କିମ୍ବା ସୁଇମିଂ ଷ୍ଟ୍ରୋକ ପରି ସୂଚନା ଅନ୍ତର୍ଭୁକ୍ତ ଅଛି"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ଶୋଇବା ପର୍ଯ୍ୟାୟ ଏବଂ ଶୋଇବାର ସେସନଗୁଡ଼ିକ ପରି ସୂଚନା ଏହି ଡାଟାରେ ଅନ୍ତର୍ଭୁକ୍ତ ଅଛି"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"ସମସ୍ତ ଏଣ୍ଟ୍ରି ଦେଖନ୍ତୁ"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"ଏହି ଡାଟାକୁ ଡିଲିଟ କରନ୍ତୁ"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"ଆପଣଙ୍କ ସ୍ୱାସ୍ଥ୍ୟ ଡାଟାକୁ ଆକ୍ସେସ କରନ୍ତୁ"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ବ୍ୟାୟାମର ମାର୍ଗ"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"ବ୍ୟାୟାମର ମାର୍ଗ ତିଆରି କରନ୍ତୁ"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"ବ୍ୟାୟାମର ମାର୍ଗକୁ ପଢ଼ନ୍ତୁ"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"ସମସ୍ତ ବ୍ୟାୟାମ ରୁଟ ପଢ଼ନ୍ତୁ"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"ଦୂରତା"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"ଦୂରତା"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"ଦୂରତାର ଡାଟା ପଢ଼ନ୍ତୁ"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"ବିଶ୍ରାମ କରିବା ସମୟରେ ହାର୍ଟ ରେଟ"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"ବିଶ୍ରାମ କରିବା ସମୟରେ ହାର୍ଟ ରେଟର ଡାଟା ପଢ଼ନ୍ତୁ"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"ବିଶ୍ରାମ କରିବା ସମୟରେ ହାର୍ଟ ରେଟର ଡାଟା ଲେଖନ୍ତୁ"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"ସ୍କିନ ତାପମାତ୍ରା"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"ସ୍କିନ ତାପମାତ୍ରା"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"ସ୍କିନ ତାପମାତ୍ରା ପଢ଼ନ୍ତୁ"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"ସ୍କିନ ତାପମାତ୍ରା ଲେଖନ୍ତୁ"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"ପଢ଼ିବା ପାଇଁ “<xliff:g id="APP_NAME">%1$s</xliff:g>”କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"ଲେଖିବା ପାଇଁ “<xliff:g id="APP_NAME">%1$s</xliff:g>”କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"ବାତିଲ କରନ୍ତୁ"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect ଡାଟା ଡିଲିଟ କରାଯାଉଛି"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect ଡାଟା ଡିଲିଟ କରାଯାଉଛି"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"ଡାଟା ଡିଲିସନ"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"ଡାଟା ଏଣ୍ଟ୍ରିକୁ ଡିଲିଟ କରନ୍ତୁ"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"ଏଣ୍ଟ୍ରିକୁ ଡିଲିଟ କରନ୍ତୁ"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ଡାଟା ଏଣ୍ଟ୍ରିକୁ ଡିଲିଟ କରନ୍ତୁ"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ଏଣ୍ଟ୍ରିକୁ ଡିଲିଟ କରନ୍ତୁ"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"ମୋଟ: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 ୱାଟ}other{# ୱାଟ}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ୱାଟ}other{# ୱାଟ}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"ତଳକୁ ମୁଭ କରନ୍ତୁ"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ଶୀର୍ଷକୁ ମୁଭ କରନ୍ତୁ"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"ନିମ୍ନକୁ ମୁଭ କରନ୍ତୁ"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"ପ୍ରାଥମିକତା ତାଲିକାରୁ <xliff:g id="SELECTED_APP">%s</xliff:g>କୁ କାଢ଼ି ଦେବା ପାଇଁ ବଟନ"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"ରିଅର୍ଡର କରିବାକୁ ଦୁଇଥର ଟାପ କରି ଡ୍ରାଗ କରନ୍ତୁ"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ଫିଟନେସ, ସୁସ୍ଥତା"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"ଅନୁମତିଗୁଡ଼ିକ"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, ସ୍ୱାସ୍ଥ୍ୟ ଡାଟା, ସ୍ୱାସ୍ଥ୍ୟର ବର୍ଗ, ଡାଟା ଆକ୍ସେସ, କାର୍ଯ୍ୟକଳାପ, ଶରୀର ପରିମାପ, ସାଇକେଲ ଟ୍ରାକିଂ, ନ୍ୟୁଟ୍ରିସନ, ଶୋଇବା, ଭାଇଟାଲ"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"ଆପଣଙ୍କ ବ୍ୟାୟାମ ରୁଟଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ କେବଳ ଆପଣ ଅନୁମତି ଦେଉଥିବା ଆପ୍ସ"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"ମୁଁ କିପରି ଆକ୍ସେସକୁ ପରିଚାଳନା କରିପାରିବି?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Health Connect ସେଟିଂସରେ ଆପଣ ବ୍ୟାୟାମ ରୁଟଗୁଡ଼ିକୁ ଆପର ଆକ୍ସେସକୁ ପରିଚାଳନା କରିପାରିବେ"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"ପଛକୁ ଫେରନ୍ତୁ"</string>
     <string name="loading" msgid="2526615755685950317">"ଲୋଡ ହେଉଛି…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"ଇଣ୍ଟିଗ୍ରେସନ ଚାଲିଛି"</string>
diff --git a/apk/res/values-pa/strings.xml b/apk/res/values-pa/strings.xml
index a6a8d72..da07b00 100644
--- a/apk/res/values-pa/strings.xml
+++ b/apk/res/values-pa/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"ਇਸ ਡਾਟਾ ਵਿੱਚ ਕਿਰਿਆਸ਼ੀਲ ਸਮਾਂ, ਕਸਰਤ ਦੀ ਕਿਸਮ, ਲੈਪ, ਕਸਰਤ ਕਿੰਨੀ ਵਾਰ ਦੁਹਰਾਈ ਗਈ, ਸੈਸ਼ਨ ਜਾਂ ਤੈਰਾਕੀ ਦੇ ਸਟ੍ਰੋਕਾਂ ਵਰਗੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੈ"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ਇਸ ਡਾਟਾ ਵਿੱਚ ਨੀਂਦ ਦੇ ਪੜਾਅ ਅਤੇ ਨੀਂਦ ਸੰਬੰਧੀ ਸੈਸ਼ਨਾਂ ਵਰਗੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੈ"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"ਸਾਰੇ ਇੰਦਰਾਜ ਦੇਖੋ"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"ਬਦਲੋ"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"ਇਸ ਡਾਟੇ ਨੂੰ ਮਿਟਾਓ"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"ਆਪਣੀ ਸਿਹਤ ਸੰਬੰਧੀ ਡਾਟੇ ਤੱਕ ਪਹੁੰਚ ਕਰੋ"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ਕਸਰਤ ਕਰਨ ਦਾ ਤਰੀਕਾ"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"ਕਸਰਤ ਕਰਨ ਦਾ ਤਰੀਕਾ ਲਿਖੋ"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"ਕਸਰਤ ਸੰਬੰਧੀ ਰਸਤੇ ਨੂੰ ਪੜ੍ਹੋ"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"ਕਸਰਤ ਦੇ ਸਾਰੇ ਰੂਟ ਪੜ੍ਹੋ"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"ਦੂਰੀ"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"ਦੂਰੀ"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"ਦੂਰੀ ਸੰਬੰਧੀ ਡਾਟਾ ਪੜ੍ਹੋ"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"ਆਰਾਮ ਵੇਲੇ ਦਿਲ ਦੀ ਧੜਕਣ ਸੰਬੰਧੀ ਡਾਟਾ"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"ਆਰਾਮ ਵੇਲੇ ਦਿਲ ਦੀ ਧੜਕਣ ਸੰਬੰਧੀ ਡਾਟਾ ਪੜ੍ਹੋ"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"ਆਰਾਮ ਵੇਲੇ ਦਿਲ ਦੀ ਧੜਕਣ ਸੰਬੰਧੀ ਡਾਟੇ ਦਾ ਸੰਪਾਦਨ ਕਰੋ"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"ਚਮੜੀ ਦਾ ਤਾਪਮਾਨ"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"ਚਮੜੀ ਦਾ ਤਾਪਮਾਨ"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"ਚਮੜੀ ਦਾ ਤਾਪਮਾਨ ਪੜ੍ਹੋ"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"ਚਮੜੀ ਦਾ ਤਾਪਮਾਨ ਲਿਖੋ"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ਨੂੰ ਪੜ੍ਹਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ਨੂੰ ਲਿਖਣ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"ਰੱਦ ਕਰੋ"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾ ਰਿਹਾ ਹੈ"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"ਡਾਟਾ ਮਿਟਾਉਣਾ"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"ਡਾਟਾ ਐਂਟਰੀ ਮਿਟਾਓ"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"ਇੰਦਰਾਜ ਮਿਟਾਓ"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"ਡਾਟਾ ਐਂਟਰੀ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ਨੂੰ ਮਿਟਾਓ"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"ਐਂਟਰੀ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ਨੂੰ ਮਿਟਾਓ"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"ਕੁੱਲ: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 ਵਾਟ}one{# ਵਾਟ}other{# ਵਾਟ}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ਵਾਟ}one{# ਵਾਟ}other{# ਵਾਟ}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"ਹੇਠਾਂ ਲਿਜਾਓ"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ਸਿਖਰ \'ਤੇ ਲਿਜਾਓ"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"ਹੇਠਾਂ ਵੱਲ ਲਿਜਾਓ"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"<xliff:g id="SELECTED_APP">%s</xliff:g> ਨੂੰ ਤਰਜੀਹੀ ਸੂਚੀ ਵਿੱਚੋਂ ਹਟਾਉਣ ਲਈ ਬਟਨ"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"ਮੁੜ-ਕ੍ਰਮਬੱਧ ਕਰਨ ਲਈ ਡਬਲ ਟੈਪ ਕਰ ਕੇ ਘਸੀਟੋ"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ਫਿੱਟਨੈੱਸ, ਤੰਦਰੁਸਤੀ"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"ਇਜਾਜ਼ਤਾਂ"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, ਸਿਹਤ ਸੰਬੰਧੀ ਡਾਟਾ, ਸਿਹਤ ਸੰਬੰਧੀ ਸ਼੍ਰੇਣੀਆਂ, ਡਾਟੇ ਤੱਕ ਪਹੁੰਚ, ਸਰਗਰਮੀ, ਸਰੀਰਕ ਮਾਪ, ਸਾਈਕਲ ਟਰੈਕਿੰਗ, ਪੋਸ਼ਣ, ਨੀਂਦ, ਸਿਹਤ ਸੰਬੰਧੀ ਜ਼ਰੂਰੀ ਜਾਣਕਾਰੀ"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"ਸਿਰਫ਼ ਉਹ ਐਪਾਂ ਜਿਨ੍ਹਾਂ ਨੂੰ ਤੁਸੀਂ ਆਪਣੇ ਕਸਰਤ ਦੇ ਰੂਟਾਂ ਤੱਕ ਪਹੁੰਚ ਦੀ ਆਗਿਆ ਦਿੱਤੀ ਹੈ"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"ਮੈਂ ਪਹੁੰਚ ਦਾ ਪ੍ਰਬੰਧਨ ਕਿਵੇਂ ਕਰਾਂ?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"ਤੁਸੀਂ Health Connect ਦੀਆਂ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਕਸਰਤ ਦੇ ਰੂਟਾਂ ਲਈ ਐਪ ਤੱਕ ਪਹੁੰਚ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦੇ ਹੋ"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"ਪਿੱਛੇ ਜਾਓ"</string>
     <string name="loading" msgid="2526615755685950317">"ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"ਏਕੀਕਰਨ ਜਾਰੀ ਹੈ"</string>
diff --git a/apk/res/values-pl/strings.xml b/apk/res/values-pl/strings.xml
index 0624864..930e670 100644
--- a/apk/res/values-pl/strings.xml
+++ b/apk/res/values-pl/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Te dane obejmują informacje takie jak czas aktywności, typ ćwiczenia, okrążenia, powtórzenia, sesje i ruchy podczas pływania"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Te dane obejmują informacje takie jak fazy i sesje snu"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Zobacz wszystkie wpisy"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"zmień"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Usuń te dane"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"dostęp do Twoich danych dotyczących zdrowia"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"trasa ćwiczeń"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Zapisz trasę ćwiczeń"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Odczyt trasy ćwiczeń"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Odczytuj wszystkie trasy ćwiczeń"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Odległość"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"odległość"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Odczytuj dane o odległości"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"tętno spoczynkowe"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Odczytuj dane o tętnie spoczynkowym"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Zapisuj dane o tętnie spoczynkowym"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura ciała"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura ciała"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Odczytuj temperaturę ciała"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Zapisuj temperaturę ciała"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Zezwól aplikacji „<xliff:g id="APP_NAME">%1$s</xliff:g>” na odczytywanie"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Zezwól aplikacji „<xliff:g id="APP_NAME">%1$s</xliff:g>” na zapisywanie"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Anuluj"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Usuwam dane z Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Usuwam dane z Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Usuwanie danych"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Usuń wpis z danymi"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Usuń wpis"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Usuń wpis z danymi <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Usuń wpis <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Łącznie: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}few{# W}many{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 wat}few{# waty}many{# watów}other{# wata}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Przenieś w dół"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Przenieś na początek"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Przenieś na koniec"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Przycisk usuwania aplikacji <xliff:g id="SELECTED_APP">%s</xliff:g> z listy priorytetów"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Aby zmienić kolejność, kliknij dwukrotnie i przeciągnij"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, samopoczucie"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"uprawnienia"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, dane dotyczące zdrowia, kategorie zdrowotne, dostęp do danych, aktywność, pomiary ciała, trasa rowerowa, odżywianie, sen, parametry życiowe"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Tylko aplikacje, którym zezwalasz na dostęp do swoich tras ćwiczeń"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Jak mogę zarządzać dostępem?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Dostępem aplikacji do tras ćwiczeń możesz zarządzać w ustawieniach Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Wstecz"</string>
     <string name="loading" msgid="2526615755685950317">"Ładuję…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Trwa integracja"</string>
diff --git a/apk/res/values-pt-rPT/strings.xml b/apk/res/values-pt-rPT/strings.xml
index f8d92c9..928bfc2 100644
--- a/apk/res/values-pt-rPT/strings.xml
+++ b/apk/res/values-pt-rPT/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Estes dados incluem informações como o tempo de atividade, o tipo de exercício, as voltas, as repetições, as sessões ou as braçadas de natação"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Estes dados incluem informações como as fases do sono e as sessões de sono"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Ver todas as entradas"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"alterar"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Apagar estes dados"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Saúde Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"aceder aos seus dados de saúde"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"trajeto de exercício"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Escrever trajeto de exercício"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Ler o trajeto do exercício"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Leia todos os trajetos de exercício"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distância"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distância"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Ler distância"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"ritmo cardíaco em repouso"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Ler ritmo cardíaco em repouso"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Escrever ritmo cardíaco em repouso"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura da pele"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura da pele"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Ler temperatura da pele"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Escrever temperatura da pele"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Permita a leitura pela app \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Permita a escrita pela app \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Cancelar"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"A apagar dados da Saúde Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"A apagar dados da Saúde Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Eliminação de dados"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Elimine a entrada de dados"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Apagar entrada"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Elimine a entrada de dados <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Eliminar entrada <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watts}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Mover para baixo"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Mover para o início"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Mover para o fim"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Botão que remove a app <xliff:g id="SELECTED_APP">%s</xliff:g> da lista de prioridades"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Toque duas vezes e arraste para reordenar"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, bem-estar"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"autorizações"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"saúde connect, dados de saúde, categorias de saúde, acesso a dados, atividade, medições corporais, monitorização do ciclo, nutrição, sono, sinais vitais"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Apenas as apps que permite que acedam aos trajetos de exercício"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Como posso gerir o acesso?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Pode gerir o acesso das apps aos trajetos de exercício nas definições da Saúde Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Anterior"</string>
     <string name="loading" msgid="2526615755685950317">"A carregar…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integração em curso"</string>
diff --git a/apk/res/values-pt/strings.xml b/apk/res/values-pt/strings.xml
index cb8c16f..daf5c1a 100644
--- a/apk/res/values-pt/strings.xml
+++ b/apk/res/values-pt/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Esses dados incluem informações como tempo de atividade, tipo de exercício, voltas, repetições, sessões ou braçadas de natação"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Esses dados incluem informações como Estágios e sessões de sono"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Ver todas as entradas"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"mudar"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Excluir estes dados"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Conexão Saúde"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"acesse seus dados de saúde"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"trajeto do exercício"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Gravar trajeto do exercício"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Ler trajeto do exercício"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Ler todos os trajetos de exercícios"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distância"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distância"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Ler informações de distância"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"frequência cardíaca em repouso"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Ler informações de frequência cardíaca em repouso"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Gravar frequência cardíaca em repouso"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura da pele"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura da pele"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Ler temperatura da pele"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Gravar temperatura da pele"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Permitir a leitura pelo app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Permitir gravação pelo app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Cancelar"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Excluindo dados do app Conexão Saúde"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Excluindo dados do app Conexão Saúde"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Exclusão de dados"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Excluir entrada de dados"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Excluir entrada"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Excluir a entrada de dados \"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>\""</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Excluir a entrada \"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>\""</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}one{# watt}other{# watts}}"</string>
@@ -504,7 +510,7 @@
     <string name="activity_type_australian_football" msgid="431838050917315084">"Futebol australiano"</string>
     <string name="sleep_session_default" msgid="7376764686701487196">"<xliff:g id="DURATION"> %1$s</xliff:g> dormindo"</string>
     <string name="sleep_stage_default" msgid="1539043695578480733">"<xliff:g id="DURATION">%1$s</xliff:g> <xliff:g id="NAME">%2$s</xliff:g>⁠"</string>
-    <string name="sleep_stage_awake" msgid="4526767634444460862">"em vigília"</string>
+    <string name="sleep_stage_awake" msgid="4526767634444460862">"acordado"</string>
     <string name="sleep_stage_awake_in_bed" msgid="5533385496857888503">"na cama sem estar dormindo"</string>
     <string name="sleep_stage_sleeping" msgid="5122840110107303518">"dormindo"</string>
     <string name="sleep_stage_out_of_bed" msgid="522297068981578046">"fora da cama"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Mover para baixo"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Mover para o início"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Mover para o fim"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Botão para remover <xliff:g id="SELECTED_APP">%s</xliff:g> da lista de prioridades"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Toque duas vezes e arraste para reordenar"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"condicionamento físico, bem-estar"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"permissões"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"conexão saúde, dados de saúde, categorias de saúde, acesso aos dados, atividade, medidas corporais, monitoramento de ciclo, nutrição, sono, sinais vitais"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Apenas os apps com permissão têm acesso às suas rotas de treino"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Como posso gerenciar o acesso?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Você pode gerenciar o acesso de apps às rotas de treino nas configurações do app Conexão Saúde"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Voltar"</string>
     <string name="loading" msgid="2526615755685950317">"Carregando…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integração em andamento"</string>
diff --git a/apk/res/values-ro/strings.xml b/apk/res/values-ro/strings.xml
index 3e2c926..b634422 100644
--- a/apk/res/values-ro/strings.xml
+++ b/apk/res/values-ro/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Aceste date includ informații precum durata activităților, tipul de exerciții, ture, repetiții, sesiuni sau mișcări de înot"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Aceste date includ informații precum fazele somnului și sesiunile de somn"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Vezi toate intrările"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"modifică"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Șterge datele"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"să-ți acceseze datele despre sănătate"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"traseul pentru exerciții"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Scrie traseul pentru exerciții"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Citește despre moduri de a exersa"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Citește toate traseele pentru exerciții"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distanță"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distanță"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Să citească distanța"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"ritm cardiac de repaus"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Să citească ritmul cardiac de repaus"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Să scrie ritmul cardiac de repaus"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura pielii"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura pielii"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Citește temperatura pielii"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Scrie temperatura pielii"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Permite aplicației <xliff:g id="APP_NAME">%1$s</xliff:g> să citească"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Permite aplicației <xliff:g id="APP_NAME">%1$s</xliff:g> să scrie"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Anulează"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Se șterg datele Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Se șterg datele Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Ștergerea datelor"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Șterge intrarea de date"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Șterge intrarea"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Șterge intrarea de date <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Șterge intrarea <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}few{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}few{# wați}other{# de wați}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Mută în jos"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Mută la început"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Mută la sfârșit"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Buton pentru eliminarea <xliff:g id="SELECTED_APP">%s</xliff:g> din lista prioritară"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Atinge de două ori și trage pentru a reordona"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"permisiuni"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, informații de sănătate, categorii de sănătate, acces la date, activitate, măsurători corporale, urmărirea ciclului menstrual, nutriție, somn, semne vitale"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Doar aplicațiile cărora le permiți accesul la traseele pentru exerciții"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Cum pot gestiona accesul?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Poți gestiona accesul aplicațiilor la traseele pentru exerciții în setările Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Înapoi"</string>
     <string name="loading" msgid="2526615755685950317">"Se încarcă…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integrare în curs"</string>
diff --git a/apk/res/values-ru/strings.xml b/apk/res/values-ru/strings.xml
index 79d561f..9718409 100644
--- a/apk/res/values-ru/strings.xml
+++ b/apk/res/values-ru/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Сведения о времени и типе тренировок, количестве кругов, повторений, подходов, гребков и т. д."</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Сведения о сне, например о его фазах."</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Посмотреть все записи"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"изменить"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Удалить эти данные"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Здоровье и спорт"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"доступ к вашим данным о здоровье"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"маршрут тренировки"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Запись маршрута тренировки"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Чтение маршрута тренировки"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Читать все маршруты тренировок"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Расстояние"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"расстояние"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Чтение данных о расстоянии"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"пульс в покое"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Чтение данных о пульсе в покое"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Запись данных о пульсе в покое"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Температура кожи"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"температура кожи"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Доступ к данным о температуре кожи"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Запись данных о температуре кожи"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"<xliff:g id="APP_NAME">%1$s</xliff:g>: разрешение на чтение"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"<xliff:g id="APP_NAME">%1$s</xliff:g>: разрешение на запись"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Отмена"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Удаление данных приложения \"Здоровье и спорт\""</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Удаление данных приложения \"Здоровье и спорт\""</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Удаление данных"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Удалить запись"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Удалить запись"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Удалить запись \"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>\""</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Удалить запись \"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>\""</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Всего: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 Вт}one{# Вт}few{# Вт}many{# Вт}other{# Вт}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ватт}one{# ватт}few{# ватта}many{# ватт}other{# ватта}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Переместить вниз"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Переместить в начало"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Переместить в конец"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Кнопка – убрать приложение \"<xliff:g id="SELECTED_APP">%s</xliff:g>\" из приоритетных"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Нажмите дважды и перетащите, чтобы упорядочить"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"физическая активность, здоровый образ жизни"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"разрешения"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"здоровье и спорт, данные о здоровье, категории данных о здоровье, доступ к данным, активность, физические параметры, отслеживание цикла, питание, сон, жизненные показатели"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Доступ к маршрутам тренировок будет только у выбранных вами приложений."</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Как управлять доступом?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"В настройках сервиса \"Здоровье и спорт\" можно задать параметры доступа приложений к маршрутам тренировок."</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Назад"</string>
     <string name="loading" msgid="2526615755685950317">"Загрузка…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Выполняется интеграция"</string>
diff --git a/apk/res/values-si/strings.xml b/apk/res/values-si/strings.xml
index e502356..77bfb77 100644
--- a/apk/res/values-si/strings.xml
+++ b/apk/res/values-si/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"මෙම දත්තවල ක්‍රියාකාරී වේලාව, ව්‍යායාම වර්ගය, වට, පුනරාවර්තන, සැසි, හෝ පිහිනුම් පහරවල් වැනි තොරතුරු ඇතුළත් වේ"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"මෙම දත්තවලට නින්දේ අදියර සහ නින්ද සැසි වැනි තොරතුරු ඇතුළත් වේ"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"සියලු ඇතුළත් කිරීම් බලන්න"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"වෙනස් කරන්න"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"මෙම දත්ත මකන්න"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"ඔබේ සෞඛ්‍ය දත්ත වෙත ප්‍රවේශය"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ව්‍යායාම මාර්ගය"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"ව්‍යායාම මාර්ගය ලියන්න"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"ව්‍යායාම මාර්ගය කියවන්න"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"සියලු ව්‍යායාම මාර්ග කියවන්න"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"දුර"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"දුර"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"දුර කියවන්න"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"විවේකී හෘද ස්පන්දන වේගය"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"විවේකී හෘද ස්පන්දන වේගය කියවන්න"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"විවේකී හෘද ස්පන්දන වේගය ලියන්න"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"සමේ උෂ්ණත්වය"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"සමේ උෂ්ණත්වය"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"සමේ උෂ්ණත්වය කියවන්න"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"සමේ උෂ්ණත්වය ලියන්න"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” හට කියවීමට ඉඩ දෙන්න"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” හට ලිවීමට ඉඩ දෙන්න"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"අවලංගු කරන්න"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect දත්ත මැකීම"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect දත්ත මැකීම"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"දත්ත මකා දැමීම"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"දත්ත ඇතුළත් කිරීම මකන්න"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"ඇතුළත් කිරීම මකන්න"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"දත්ත ඇතුළත් කිරීම <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> මකන්න"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"ඇතුළත් කිරීම <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> මකන්න"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"එකතුව: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{වොට් 1 ක්}one{වොට් # ක්}other{වොට් # ක්}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"පහළට ගෙන යන්න"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ඉහළට ගෙන යන්න"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"පතුළට ගෙන යන්න"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"ප්‍රමුඛතා ලැයිස්තුවෙන් <xliff:g id="SELECTED_APP">%s</xliff:g> ඉවත් කිරීමට බොත්තම"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"යළි අනුපිළිවෙලට සැකසීමට දෙවරක් තට්ටු කර අදින්න"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"යෝග්‍යතාව, සුවතාවය"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"අවසර"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, සෞඛ්‍ය දත්ත, සෞඛ්‍ය ප්‍රවර්ග, දත්ත ප්‍රවේශය, ක්‍රියාකාරකම්, ශරීර මිනුම්, ඔසප් චක්‍ර ලුහුබැඳීම, පෝෂණය, නින්ද, vitals"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"ඔබේ ව්‍යායාම මාර්ග වෙත ප්‍රවේශ වීමට ඔබ ඉඩ දෙන යෙදුම් පමණි"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"මට ප්‍රවේශය කළමනා කළ හැක්කේ කෙසේද?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Health Connect සැකසීම් තුළ ඔබට ව්‍යායාම් මාර්ග වෙත ප්‍රවේශය කළමනා කළ හැක"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"ආපසු"</string>
     <string name="loading" msgid="2526615755685950317">"පූරණය කරමින්…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"ඒකාබද්ධ කිරීම සිදු වෙමින් පවතී"</string>
diff --git a/apk/res/values-sk/strings.xml b/apk/res/values-sk/strings.xml
index bce2c9e..f0802f6 100644
--- a/apk/res/values-sk/strings.xml
+++ b/apk/res/values-sk/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Tieto údaje zahrnujú informácie ako čas aktivity, typ cvičenia, kolá, opakovania, série alebo plavecké tempá"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Tieto údaje zahrnujú informácie ako fázy a relácie spánku"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Zobraziť všetky záznamy"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"zmeniť"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Odstrániť tieto údaje"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Dáta o zdraví"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"prístup k vašim údajom o zdraví"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"trasa cvičenia"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Zapisovať trasu cvičenia"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Čítať trasu cvičenia"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Čítať všetky trasy cvičenia"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Vzdialenosť"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"vzdialenosť"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Čítanie údajov o vzdialenosti"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"pokojový pulz"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Čítanie údajov o pokojovom pulze"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Zapisovanie údajov o pokojovom pulze"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Teplota pokožky"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"teplota pokožky"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Čítať teplotu pokožky"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Zapisovať teplotu pokožky"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Povolenie aplikácii <xliff:g id="APP_NAME">%1$s</xliff:g> čítať"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Povolenie aplikácii <xliff:g id="APP_NAME">%1$s</xliff:g> zapisovať"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Zrušiť"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Odstraňujú sa údaje Dát o zdraví"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Odstraňujú sa údaje Dát o zdraví"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Údaje sa odstraňujú"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Odstrániť záznam údajov"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Odstrániť záznam"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Odstrániť záznam údajov <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Odstrániť záznam <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Celkove: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}few{# W}many{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}few{# watty}many{# wattu}other{# wattov}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Presunúť nadol"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Presunúť na začiatok"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Presunúť na koniec"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Tlačidlo na odstránenie apl. <xliff:g id="SELECTED_APP">%s</xliff:g> zo zozn. prioritných"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Poradie zmeníte dvojitým klepnutím a presunutím"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"kondícia, zdravý životný štýl"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"povolenia"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"dáta o zdraví, údaje o zdraví, kategórie zdravotných informácií, prístup k údajom, aktivita, telesné miery, sledovanie cyklu, výživa, spánok, životné funkcie"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Iba aplikácie, ktorým povolíte prístup k trasám cvičenia"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Ako môžem spravovať prístup?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Prístup aplikácie k trasám cvičenia môžete spravovať v nastaveniach Dát o zdraví"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Späť"</string>
     <string name="loading" msgid="2526615755685950317">"Načítava sa…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integruje sa"</string>
diff --git a/apk/res/values-sl/strings.xml b/apk/res/values-sl/strings.xml
index e8d810d..d7d3e92 100644
--- a/apk/res/values-sl/strings.xml
+++ b/apk/res/values-sl/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Ti podatki vključujejo informacije, kot so čas dejavnosti, vrsta vadbe, število krogov, ponovitev, sej ali plavalnih zamahov."</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Ti podatki vključujejo informacije, kot so faze in seje spanja."</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Ogled vseh vnosov"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"spremeni"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Izbriši te podatke"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"dostop do podatkov o zdravju"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"vadbena pot"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Zapisovanje vadbene poti"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Branje vadbene poti"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Branje vseh vadbenih poti"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Razdalja"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"razdalja"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Branje razdalje"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"srčni utrip v mirovanju"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Branje srčnega utripa v mirovanju"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Zapisovanje srčnega utripa v mirovanju"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura kože"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura kože"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Branje temperature kože"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Zapisovanje temperature kože"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Dovoljevanje branja aplikaciji »<xliff:g id="APP_NAME">%1$s</xliff:g>«"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Dovoljevanje pisanja aplikaciji »<xliff:g id="APP_NAME">%1$s</xliff:g>«"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Prekliči"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Brisanje podatkov storitve Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Brisanje podatkov storitve Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Brisanje podatkov"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Izbris vnosa podatkov"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Izbriši vnos"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Izbris vnosa podatkov »<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>«"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Izbriši vnos »<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>«"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Skupaj: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}two{# W}few{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vat}one{# vat}two{# vata}few{# vati}other{# vatov}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Premik navzdol"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Premik na vrh"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Premik na dno"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Gumb za odstranitev aplikacije <xliff:g id="SELECTED_APP">%s</xliff:g> s prednostnega seznama"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Dvakrat se dotaknite in povlecite za prerazporeditev"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"telesna pripravljenost, dobro počutje"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"dovoljenja"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, podatki o zdravju, kategorije zdravja, dostop do podatkov, dejavnost, telesne meritve, spremljanje cikla, prehrana, spanje, spanec, osnovni podatki"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Samo aplikacije, ki jim dovolite dostop do vadbenih poti."</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Kako lahko upravljam dostop?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Dostop aplikacij do vadbenih poti lahko upravljate v nastavitvah za Health Connect."</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Nazaj"</string>
     <string name="loading" msgid="2526615755685950317">"Nalaganje …"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integracija je v teku"</string>
diff --git a/apk/res/values-sq/strings.xml b/apk/res/values-sq/strings.xml
index 194daeb..314fe45 100644
--- a/apk/res/values-sq/strings.xml
+++ b/apk/res/values-sq/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Këto të dhëna përfshijnë informacione si p.sh. koha aktive, lloji i ushtrimeve, xhirot, përsëritjet, seancat ose stilet e notit"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Këto të dhëna përfshijnë informacione si p.sh. fazat e gjumit dhe seancat e gjumit"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Shiko të gjitha hyrjet"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"ndrysho"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Fshi këto të dhëna"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"të ketë qasje te të dhënat e tua të shëndetit"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"itinerari i stërvitjes"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Të shkruajë itinerarin e stërvitjes"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Lexo itinerarin e stërvitjes"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Të lexojë të gjitha itineraret e stërvitjeve"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Distanca"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"distanca"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Të lexojë të dhënat për distancën"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"rrahjet e zemrës në gjendje qetësie"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Të lexojë të dhënat për rrahjet e zemrës në gjendje qetësie"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Të shkruajë të dhënat për rrahjet e zemrës në gjendje qetësie"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura e lëkurës"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura e lëkurës"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Lexo temperaturën e lëkurës"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Shkruaj temperaturën e lëkurës"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Lejo \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" të lexojë"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Lejo \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" të shkruajë"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Anulo"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Të dhënat e Health Connect po fshihen"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Të dhënat e Health Connect po fshihen"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Fshirja e të dhënave"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Fshi regjistrimin e të dhënave"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Fshi hyrjen"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Fshi hyrjen e të dhënave: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Fshi hyrjen: <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Në total: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vat}other{# vat}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Zhvendos poshtë"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Zhvendos në krye"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Zhvendos në fund"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Butoni për të hequr \"<xliff:g id="SELECTED_APP">%s</xliff:g>\" nga lista e përparësisë"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Trokit dy herë dhe zvarrit për të ndryshuar renditjen"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitnesi, mirëqenia"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"lejet"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, të dhënat e shëndetit, kategoritë e shëndetit, qasja te të dhënat, aktiviteti, matjet e trupit, monitorimi i ciklit menstrual, të ushqyerit, gjumi, të dhënat jetësore"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Vetëm aplikacionet që ti lejon të kenë qasje tek itineraret e stërvitjes"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Si mund ta menaxhoj qasjen?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Mund ta menaxhosh qasjen e aplikacionit tek itineraret e stërvitjes te cilësimet e Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Prapa"</string>
     <string name="loading" msgid="2526615755685950317">"Po ngarkohet…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integrimi në proces"</string>
diff --git a/apk/res/values-sr/strings.xml b/apk/res/values-sr/strings.xml
index ea66fb1..57365b8 100644
--- a/apk/res/values-sr/strings.xml
+++ b/apk/res/values-sr/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Ови подаци обухватају информације попут времена активности, типа вежбања, кругова, понављања, сесија или завеслаја"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Ови подаци обухватају информације попут фаза сна и сесија спавања"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Прикажи све ставке"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"промени"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Избриши ове податке"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Повезивање здравља"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"приступ подацима о здрављу"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"рута вежбања"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Уписивање руте вежбања"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Читање руте вежбања"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Читај све руте вежбања"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Раздаљина"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"раздаљина"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Читање података о раздаљини"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"пулс у мировању"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Читање података о пулсу у мировању"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Уписивање података о пулсу у мировању"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Температура коже"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"температура коже"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Читај податке о температури коже"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Уписуј податке о температури коже"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Дозвола да <xliff:g id="APP_NAME">%1$s</xliff:g> очитава податке"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Дозвола да <xliff:g id="APP_NAME">%1$s</xliff:g> уписује податке"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Откажи"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Бришу се подаци Повезивања здравља"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Бришу се подаци Повезивања здравља"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Брисање података"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Избриши унос података"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Избриши унос"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Избриши унос података <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Избриши унос <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Укупно: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}few{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ват}one{# ват}few{# вата}other{# вати}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Померите надоле"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Преместите на врх"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Преместите на дно"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Дугме за уклањање апликације <xliff:g id="SELECTED_APP">%s</xliff:g> са листе приоритета"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Двапут додирните и превуците за промену редоследа"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"фитнес, велнес"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"дозволе"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"повезивање здравља, здравствени подаци, здравствене категорије, приступ подацима, активност, телесне мере, праћење циклуса, исхрана, спавање, виталне функције"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Само апликације којима дозволите да приступају рутама за вежбање"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Како могу да управљам приступом?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Можете да управљате приступом апликација рутама за вежбање у подешавањима Повезивања здравља"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Назад"</string>
     <string name="loading" msgid="2526615755685950317">"Учитава се…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Интеграција је у току"</string>
diff --git a/apk/res/values-sv/strings.xml b/apk/res/values-sv/strings.xml
index 1aaa63b..dd28a2b 100644
--- a/apk/res/values-sv/strings.xml
+++ b/apk/res/values-sv/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Denna data omfattar information som aktiv tid, träningstyp, varv, repetitioner, sessioner eller simtag"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Denna data omfattar information som sömnstadier och sömnsessioner"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Se alla poster"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"ändra"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Radera denna data"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"åtkomst till hälsodata"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"träningsrutt"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Skapa träningsrutt"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Läs träningsrutt"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Läsa alla träningsrutter"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Sträcka"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"sträcka"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Läsbehörighet för sträcka"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"vilopuls"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Läsbehörighet för vilopuls"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Skrivbehörighet för vilopuls"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Hudtemperatur"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"hudtemperatur"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Läsa hudtemperatur"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Registrera hudtemperatur"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Ge <xliff:g id="APP_NAME">%1$s</xliff:g> läsbehörighet"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Ge <xliff:g id="APP_NAME">%1$s</xliff:g> skrivbehörighet"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Avbryt"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect-data raderas"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect-data raderas"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Radera data"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Radera datapost"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Radera post"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Radera dataposten <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Radera posten <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Totalt: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Flytta nedåt"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Flytta högst upp"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Flytta längst ned"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Knapp för att ta bort <xliff:g id="SELECTED_APP">%s</xliff:g> från prioritetslistan"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Tryck snabbt två gånger och dra för att ändra ordning"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"träning, hälsa"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"behörigheter"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, hälsodata, hälsokategorier, dataåtkomst, aktivitet, kroppsmått, registrering av menscykeln, näring, sömn, vitalparametrar"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Det är bara appar du ger åtkomst som får tillgång till dina träningsrutter"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Hur kan jag hantera åtkomst?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Du kan hantera appåtkomst till träningsrutter i inställningarna för Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Tillbaka"</string>
     <string name="loading" msgid="2526615755685950317">"Läser in …"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integrering pågår"</string>
diff --git a/apk/res/values-sw/strings.xml b/apk/res/values-sw/strings.xml
index 7569bbe..2ad5229 100644
--- a/apk/res/values-sw/strings.xml
+++ b/apk/res/values-sw/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Data hii inajumuisha maelezo kama vile muda uliotumia kufanya mazoezi, aina ya mazoezi, mizunguko, marudio, vipindi au mitindo ya kuogelea"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Data hii inajumuisha maelezo kama vile hatua za kulala na vipindi vya kulala"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Angalia data yote"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"badilisha"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Futa data hii"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"Ifikie data yako ya afya"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"njia ya mazoezi"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Andika njia ya mazoezi"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Soma njia ya mazoezi"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Kusoma njia zote za mazoezi"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Umbali"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"umbali"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Isome data ya umbali"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"mapigo ya moyo ya kawaida"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Isome data ya mapigo ya moyo ya kawaida"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Iandike data ya mapigo ya moyo ya kawaida"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Kiwango cha joto kwenye ngozi"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"kiwango cha joto kwenye ngozi"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Soma kiwango cha joto kwenye ngozi"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Andika kiwango cha joto kwenye ngozi"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Ruhusu “<xliff:g id="APP_NAME">%1$s</xliff:g>” isome"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Ruhusu “<xliff:g id="APP_NAME">%1$s</xliff:g>” ili uandike"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Ghairi"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Inafuta data ya Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Inafuta data ya Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Kufuta data"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Futa data"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Futa data"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Futa data ya <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Futa data ya <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Jumla: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{Wati 1}other{Wati #}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{Wati 1}other{Wati #}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Sogeza chini"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Hamishia juu"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Hamishia chini"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Kitufe cha kuondoa <xliff:g id="SELECTED_APP">%s</xliff:g> kwenye orodha ya vipaumbele"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Gusa mara mbili kisha uburute ili upange upya"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"siha, afya"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"ruhusa"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, data ya afya, aina ya afya, ufikiaji wa data, shughuli, vipimo vya mwili, ufuatiliaji wa hedhi, lishe, data ya usingizi, vipimo muhimu"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Programu unazoruhusu tu kufikia njia zako za mazoezi"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Ninawezaje kudhibiti ufikiaji?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Unaweza kudhibiti ufikiaji wa njia za mazoezi wa programu katika mipangilio ya Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Nyuma"</string>
     <string name="loading" msgid="2526615755685950317">"Inapakia…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Shughuli ya ujumuishaji inaendelea"</string>
diff --git a/apk/res/values-ta/strings.xml b/apk/res/values-ta/strings.xml
index 3d01298..38c2818 100644
--- a/apk/res/values-ta/strings.xml
+++ b/apk/res/values-ta/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"செயல்பாட்டு நேரம், உடற்பயிற்சி வகை, சுற்றுகள், மீண்டும் செய்தல், அமர்வுகள், ஸ்விம்மிங் ஸ்ட்ரோக்குகள் போன்ற தகவல்கள் இந்தத் தரவில் உள்ளடங்கும்"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"உறக்க நிலைகள், உறக்கநேர அமர்வுகள் போன்ற தகவல்கள் இந்தத் தரவில் உள்ளடங்கும்"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"அனைத்து உள்ளீடுகளையும் காட்டு"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"மாற்று"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"இந்தத் தரவை நீக்கு"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"உங்கள் உடல் ஆரோக்கியம் தொடர்பான தரவை அணுகும்"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"உடற்பயிற்சிப் பாதை"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"உடற்பயிற்சிப் பாதை தொடர்பான தரவை எழுதும்"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"உடற்பயிற்சிப் பாதையைப் படியுங்கள்"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"உடற்பயிற்சிக்கான வழிகள் அனைத்தையும் வாசி"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"தொலைவு"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"தொலைவு"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"தொலைவு தொடர்பான தரவை வாசிக்கும்"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"ஓய்வுநிலை இதயத் துடிப்பு"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"ஓய்வுநிலை இதயத் துடிப்பு தொடர்பான தரவை வாசிக்கும்"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"ஓய்வுநிலை இதயத் துடிப்பு தொடர்பான தரவை எழுதும்"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"தோல் வெப்பநிலை"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"தோல் வெப்பநிலை"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"தோல் வெப்பநிலையைப் படி"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"தோல் வெப்பநிலையை எழுது"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"படிக்க “<xliff:g id="APP_NAME">%1$s</xliff:g>” ஆப்ஸை அனுமதிக்கவும்"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"எழுத “<xliff:g id="APP_NAME">%1$s</xliff:g>” ஆப்ஸை அனுமதிக்கவும்"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"ரத்துசெய்"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect தரவை நீக்குகிறது"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect தரவை நீக்குகிறது"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"தரவு நீக்கம்"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"தரவு உள்ளீட்டை நீக்கும்"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"உள்ளீட்டை நீக்கு"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> தரவு உள்ளீட்டை நீக்கும்"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> உள்ளீட்டை நீக்கு"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"மொத்தம்: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 வாட்}other{# வாட்}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 வாட்}other{# வாட்}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"கீழே நகர்த்து"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"மேற்புறத்திற்கு நகர்த்து"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"கீழ்ப்புறத்திற்கு நகர்த்து"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"முன்னுரிமைப் பட்டியலில் இருந்து <xliff:g id="SELECTED_APP">%s</xliff:g> ஐ அகற்றும் பட்டன்"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"மறுவரிசைப்படுத்த இருமுறை தட்டி இழுக்கவும்"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"உடற்பயிற்சி, ஆரோக்கியம்"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"அனுமதிகள்"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, உடல்நலத் தரவு, உடல்நல வகைகள், தரவு அணுகல், செயல்பாடு, உடல் அளவீடுகள், சைக்கிள் டிராக்கிங், ஊட்டச்சத்து, உறக்கம், உடல் இயக்க அளவீடுகள்"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"உங்கள் உடற்பயிற்சிப் பாதைகளை அணுக நீங்கள் அனுமதிக்கும் ஆப்ஸ் மட்டும்"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"அணுகலை நான் எப்படி நிர்வகிப்பது?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Health Connect அமைப்புகளில் உடற்பயிற்சிப் பாதைகளுக்கான ஆப்ஸ் அணுகலை நீங்கள் நிர்வகிக்கலாம்"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"பின்செல்"</string>
     <string name="loading" msgid="2526615755685950317">"ஏற்றுகிறது…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"ஒருங்கிணைப்பு செயலிலுள்ளது"</string>
diff --git a/apk/res/values-te/strings.xml b/apk/res/values-te/strings.xml
index 920331e..2985edc 100644
--- a/apk/res/values-te/strings.xml
+++ b/apk/res/values-te/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"ఈ డేటాలో యాక్టివ్ టైమ్, వ్యాయామ రకం, ల్యాప్‌లు, రిపిటీషన్‌లు, సెషన్‌లు, లేదా స్విమ్మింగ్ స్ట్రోక్‌లు వంటి సమాచారం ఉంటుంది"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ఈ డేటాలో నిద్ర దశలు, నిద్ర సెషన్‌ల వంటి సమాచారం ఉంటుంది"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"అన్ని ఎంట్రీలను చూడండి"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"మార్చండి"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"ఈ డేటాను తొలగించండి"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"మీ ఆరోగ్య డేటాను యాక్సెస్ చేయండి"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"వ్యాయామ విధానం"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"వ్యాయామ మార్గం గురించి రాయండి"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"వ్యాయామ మార్గాన్ని చదవండి"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"వ్యాయామ సెషన్‌కు సంబంధించిన రూట్‌లన్నింటిని చదవండి"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"దూరం"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"దూరం"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"దూరం డేటాను చదువుతుంది"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"విశ్రాంతి సమయంలో గుండె స్పందన రేటు"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"విశ్రాంతి సమయంలో గుండె స్పందన రేటు డేటాను చదువుతుంది"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"విశ్రాంతి సమయంలో గుండె స్పందన రేటు డేటాను రాస్తుంది"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"చర్మం ఉష్ణోగ్రత"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"చర్మం ఉష్ణోగ్రత"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"చర్మం ఉష్ణోగ్రతను చదవండి"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"చర్మం ఉష్ణోగ్రత గురించి రాయండి"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"చదవడానికి \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" యాప్‌ను అనుమతించండి"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"రాయడానికి \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" యాప్‌ను అనుమతించండి"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"రద్దు చేయండి"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect డేటాను తొలగిస్తోంది"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect డేటాను తొలగిస్తోంది"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"డేటా తొలగింపు"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"డేటా ఎంట్రీని తొలగించండి"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"ఎంట్రీని తొలగించండి"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> డేటా ఎంట్రీని తొలగించండి"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> ఎంట్రీని తొలగించండి"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"మొత్తం: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 వా}other{# వా}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 వాట్}other{# వాట్‌లు}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"కిందకు తరలించండి"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ఎగువకు తరలించండి"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"దిగువకు తరలించండి"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"ముఖ్యమైన లిస్ట్ నుండి <xliff:g id="SELECTED_APP">%s</xliff:g>‌ను తీసివేయడానికి బటన్"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"రీ ఆర్డర్‌లో ఉంచడానికి, డబుల్ ట్యాప్ చేసి, లాగండి."</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ఫిట్‌నెస్, సంరక్షణ"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"అనుమతులు"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, ఆరోగ్యం డేటా, ఆరోగ్యం కేటగిరీలు, డేటా యాక్సెస్, యాక్టివిటీ, శారీరక సమాచారం, సైకిల్ ట్రాకింగ్, న్యూట్రిషన్, స్లీప్, కీలక ఆరోగ్య కొలమానాలు"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"వ్యాయామ సెషన్‌కు సంబంధించిన మీ రూట్‌లను యాక్సెస్ చేయడానికి మీరు అనుమతించే యాప్‌లకు మాత్రమే"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"నేను యాక్సెస్‌ను ఎలా మేనేజ్ చేయగలను?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Health Connect సెట్టింగ్స్‌లో వ్యాయామ సెషన్‌కు సంబంధించిన రూట్‌లకు యాప్ యాక్సెస్‌ను మీరు మేనేజ్ చేయవచ్చు"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"వెనుకకు"</string>
     <string name="loading" msgid="2526615755685950317">"లోడ్ అవుతోంది…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"ఇంటిగ్రేషన్ ప్రోగ్రెస్‌లో ఉంది"</string>
diff --git a/apk/res/values-th/strings.xml b/apk/res/values-th/strings.xml
index a69b79e..c102dd1 100644
--- a/apk/res/values-th/strings.xml
+++ b/apk/res/values-th/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"ข้อมูลนี้รวมถึงข้อมูลอย่างเช่นเวลาที่เคลื่อนไหวร่างกาย ประเภทการออกกำลังกาย รอบ การทำซ้ำ เซสชัน หรือสโตรกการว่ายน้ำ"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"ข้อมูลนี้รวมถึงข้อมูลอย่างเช่นระยะการนอนหลับและเซสชันการนอนหลับ"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"ดูรายการข้อมูลทั้งหมด"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"เปลี่ยน"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"ลบข้อมูลนี้"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"เข้าถึงข้อมูลสุขภาพของคุณ"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"เส้นทางออกกำลังกาย"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"เขียนเส้นทางออกกำลังกาย"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"อ่านเส้นทางออกกำลังกาย"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"อ่านเส้นทางออกกำลังกายทั้งหมด"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"ระยะทาง"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"ระยะทาง"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"อ่านข้อมูลระยะทาง"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"อัตราการเต้นของหัวใจขณะพัก"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"อ่านข้อมูลอัตราการเต้นของหัวใจขณะพัก"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"เขียนข้อมูลอัตราการเต้นของหัวใจขณะพัก"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"อุณหภูมิผิวหนัง"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"อุณหภูมิผิวหนัง"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"อ่านข้อมูลอุณหภูมิผิวหนัง"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"เขียนข้อมูลอุณหภูมิผิวหนัง"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"อนุญาตให้ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" อ่าน"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"อนุญาตให้ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" เขียน"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"ยกเลิก"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"กำลังลบข้อมูล Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"กำลังลบข้อมูล Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"การลบข้อมูล"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"ลบรายการข้อมูล"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"ลบรายการข้อมูล"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"ลบรายการข้อมูล <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"ลบรายการ <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"รวม: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 วัตต์}other{# วัตต์}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 วัตต์}other{# วัตต์}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"เลื่อนลง"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"ย้ายไปด้านบนสุด"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"ย้ายไปด้านล่างสุด"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"ปุ่มสำหรับนำ <xliff:g id="SELECTED_APP">%s</xliff:g> ออกจากรายการสำคัญ"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"แตะสองครั้งแล้วลากเพื่อจัดเรียงใหม่"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ฟิตเนส, ความแข็งแรงสมบูรณ์"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"สิทธิ์"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"Health Connect, ข้อมูลสุขภาพ, หมวดหมู่สุขภาพ, การเข้าถึงข้อมูล, กิจกรรม, การตรวจวัดร่างกาย, การติดตามรอบเดือน, โภชนาการ, การนอนหลับ, ค่าสัญญาณชีพ"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"เฉพาะแอปที่คุณอนุญาตให้เข้าถึงเส้นทางออกกำลังกาย"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"ฉันจะจัดการการเข้าถึงได้อย่างไร"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"คุณจัดการการเข้าถึงเส้นทางออกกำลังกายของแอปได้ในการตั้งค่า Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"กลับ"</string>
     <string name="loading" msgid="2526615755685950317">"กำลังโหลด…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"การผสานรวมอยู่ระหว่างดำเนินการ"</string>
diff --git a/apk/res/values-tl/strings.xml b/apk/res/values-tl/strings.xml
index 8ee6619..3bfa17f 100644
--- a/apk/res/values-tl/strings.xml
+++ b/apk/res/values-tl/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Kasama sa data na ito ang impormasyon tulad ng oras na aktibo, uri ng ehersisyo, mga lap, mga pag-uulit, mga session, o mga swimming stroke"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Kasama sa data na ito ang impormasyon tulad ng mga yugto ng pagtulog at session ng pagtulog"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Tingnan ang lahat ng entry"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"baguhin"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"I-delete ang data na ito"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"i-access ang iyong data ng kalusugan"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ruta ng pag-eehersisyo"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Sumulat ng ruta ng pag-eehersisyo"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"I-read ang ruta ng pag-eehersisyo"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Basahin ang lahat ng ruta ng pag-e-ehersisyo"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Layo"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"layo"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"I-read ang layo"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"bilis ng tibok ng puso habang nagpapahinga"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"I-read ang bilis ng tibok ng puso habang nagpapahinga"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"I-write ang bilis ng tibok ng puso habang nagpapahinga"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Temperatura ng balat"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"temperatura ng balat"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Basahin ang temperatura ng balat"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"I-write ang temperatura ng balat"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Payagang mag-read ang “<xliff:g id="APP_NAME">%1$s</xliff:g>”"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Payagang mag-write ang “<xliff:g id="APP_NAME">%1$s</xliff:g>”"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Kanselahin"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Dine-delete ang data ng Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Dine-delete ang data ng Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Pag-delete ng data"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"I-delete ang entry ng data"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"I-delete ang entry"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"I-delete ang entry ng data na <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"I-delete ang entry na <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Kabuuan: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}one{# watts}other{# watts}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Ilipat pababa"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Ilipat sa itaas"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Ilipat sa ibaba"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Button para alisin ang <xliff:g id="SELECTED_APP">%s</xliff:g> sa listahan ng priyoridad"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"I-double tap at i-drag para ibahin ang pagkakaayos"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"mga pahintulot"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, data sa kalusugan, mga kategorya sa kalusugan, access sa data, aktibidad, mga sukat ng katawan, cycle pag-track, nutrisyon, tulog, vitals"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Ang mga app lang na papayagan mong mag-access ng iyong mga ruta ng ehersisyo"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Paano ko mapapamahalaan ang access?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Mapapamahalaan mo ang access ng app sa mga ruta ng ehersisyo sa mga setting ng Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Bumalik"</string>
     <string name="loading" msgid="2526615755685950317">"Naglo-load…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Isinasagawa ang pag-integrate"</string>
diff --git a/apk/res/values-tr/strings.xml b/apk/res/values-tr/strings.xml
index cee0fd2..e182c5c 100644
--- a/apk/res/values-tr/strings.xml
+++ b/apk/res/values-tr/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Aktif olunan süre, egzersiz türü, turlar, tekrarlar, seanslar ve yüzme sırasındaki kulaçlar gibi bilgiler bu verilere dahildir"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Uyku aşamaları ve uyku seansları gibi bilgiler bu verilere dahildir"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Tüm girişleri göster"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"değiştir"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Bu verileri sil"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"sağlık verinize erişme"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"egzersiz rotası"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Egzersiz rotasını yaz"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Egzersiz rotasını okuma"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Tüm egzersiz rotalarını okuma"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Mesafe"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"mesafe"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Mesafeyi oku"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"dinlenme nabzı"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Dinlenme nabzını oku"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Dinlenme nabzını yaz"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Deri sıcaklığı"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"deri sıcaklığı"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Deri sıcaklığını oku"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Deri sıcaklığını yaz"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” uygulamasına okuma izni ver"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" uygulamasına yazma izni ver"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"İptal"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect verileri siliniyor"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect verileri siliniyor"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Veri silme"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Veri girişini silin"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Girişi sil"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> veri girişini sil"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> girişini sil"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Toplam: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vat}other{# vat}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Aşağı taşı"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"En üste taşı"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"En alta taşı"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"<xliff:g id="SELECTED_APP">%s</xliff:g> uygulamasını öncelik listesinden kaldırma düğmesi"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Yeniden sıralamak için iki kez dokunup sürükleyin"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitness, sağlıklı yaşam"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"izinler"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, sağlık verileri, sağlık kategorileri, veri erişimi, aktivite, vücut ölçümleri, âdet döngüsü takibi, beslenme, uyku, hayati bulgular"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Yalnızca egzersiz rotalarınıza erişmesine izin verdiğiniz uygulamalar"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Erişimi nasıl yönetebilirim?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Uygulamaların, egzersiz rotalarına erişimini Health Connect ayarlarından yönetebilirsiniz"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Geri"</string>
     <string name="loading" msgid="2526615755685950317">"Yükleniyor…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Entegrasyon devam ediyor"</string>
diff --git a/apk/res/values-uk/strings.xml b/apk/res/values-uk/strings.xml
index d18885e..d57904a 100644
--- a/apk/res/values-uk/strings.xml
+++ b/apk/res/values-uk/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Це дані про тривалість активності, тип вправ, кількість сеансів, кіл, повторів, гребків тощо"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Це дані про фази та сеанси сну тощо"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Переглянути всі записи"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"змінити"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Видалити ці дані"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"доступ до даних про здоров’я"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"маршрут тренування"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Записувати маршрут тренування"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Зчитувати маршрут тренування"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Переглядати всі маршрути тренувань"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Відстань"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"відстань"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Зчитувати відстань"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"пульс у стані спокою"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Зчитувати дані про пульс у стані спокою"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Записувати дані про пульс у стані спокою"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Температура шкіри"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"температура шкіри"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Переглядати температуру шкіри"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Записувати температуру шкіри"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Дозволити додатку <xliff:g id="APP_NAME">%1$s</xliff:g> зчитувати дані"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Дозволити додатку <xliff:g id="APP_NAME">%1$s</xliff:g> записувати дані"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Скасувати"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Видалення даних Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Видалення даних Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Видалення даних"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Видалити запис даних"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Видалити запис"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Видалити запис даних \"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>\""</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Видалити запис \"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>\""</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Усього: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 Вт}one{# Вт}few{# Вт}many{# Вт}other{# Вт}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 ват}one{# ват}few{# вати}many{# ватів}other{# вата}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Перемістити нижче"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Перемістити вгору"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Перемістити вниз"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Кнопка видалення додатка <xliff:g id="SELECTED_APP">%s</xliff:g> зі списку пріоритетних"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Двічі торкніться й потягніть, щоб змінити порядок"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"фітнес, оздоровлення"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"дозволи"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, дані про здоров’я, категорії стану здоров’я, доступ до даних, активність, параметри тіла, відстеження циклу, харчування, сон, життєві показники"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Лише додатки, яким ви надали доступ до маршрутів тренувань"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Як можна керувати доступом?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Ви можете керувати доступом додатків до маршрутів тренувань у налаштуваннях Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Назад"</string>
     <string name="loading" msgid="2526615755685950317">"Завантаження…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Триває інтеграція"</string>
diff --git a/apk/res/values-ur/strings.xml b/apk/res/values-ur/strings.xml
index 9eda2e6..4d65fd6 100644
--- a/apk/res/values-ur/strings.xml
+++ b/apk/res/values-ur/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"اس ڈیٹا میں فعال وقت، ورزش کی قسم، لیپس، تکرار، سیشنز یا تیراکی اسٹروکس جیسی معلومات شامل ہیں"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"اس ڈیٹا میں نیند کے مراحل اور نیند کے سیشنز جیسی معلومات شامل ہیں"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"تمام اندراجات دیکھیں"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"تبدیل کریں"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"اس ڈیٹا کو حذف کریں"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"اپنی صحت سے متعلق ڈیٹا تک رسائی حاصل کریں"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"ورزش کا راستہ"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"ورزش کا راستہ لکھیں"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"ورزش کا طریقہ پڑھیں"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"ورزش کے تمام روٹس پڑھیں"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"فاصلہ"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"فاصلہ"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"فاصلے سے متعلق ڈیٹا پڑھیں"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"آرام کرتے وقت حرکت قلب کی شرح سے متعلق ڈیٹا"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"آرام کرتے وقت حرکت قلب کی شرح سے متعلق ڈیٹا پڑھیں"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"آرام کرتے وقت حرکت قلب کی شرح سے متعلق ڈیٹا لکھیں"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"جلد کا درجہ حرارت"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"جلد کا درجہ حرارت"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"جلد کا درجہ حرارت پڑھیں"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"جلد کا درجہ حرارت لکھیں"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" کو پڑھنے کی اجازت دیں"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"\"<xliff:g id="APP_NAME">%1$s</xliff:g>\" کو لکھنے کی اجازت دیں"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"منسوخ کریں"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect ڈیٹا کو حذف کیا جا رہا ہے"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect ڈیٹا کو حذف کیا جا رہا ہے"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"ڈیٹا حذف کرنا"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"ڈیٹا کے اندراج کو حذف کریں"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"اندراج حذف کریں"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"ڈیٹا کے اندراج کو حذف کریں <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"اندراج حذف کریں <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"کل: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 واٹ}other{# واٹ}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"نیچے منتقل کریں"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"سب سے اوپر منتقل کریں"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"سب سے نیچے منتقل کریں"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"ترجیح کی فہرست سے <xliff:g id="SELECTED_APP">%s</xliff:g> کو ہٹانے کیلئے بٹن"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"دوبارہ ترتیب دینے کیلئے دوبار تھپتھپائیں و گھسیٹیں"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"تندرستی، فلاح و بہبود"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"اجازتیں"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"ہیلتھ کنیکٹ، ہیلتھ ڈیٹا، صحت کے زمرے، ڈیٹا تک رسائی، سرگرمی، جسمانی پیمائشیں، سائیکل ٹریکنگ، غذائیت، نیند، وائٹلز"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"صرف وہ ایپس جنہیں آپ اپنے ورزش کے روٹس تک رسائی کی اجازت دیتے ہیں"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"میں رسائی کا نظم کیسے کر سکتا ہوں؟"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"آپ Health Connect کی ترتیبات میں ورزش کے روٹس تک ایپ کی رسائی کا نظم کر سکتے ہیں"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"پیچھے جائیں"</string>
     <string name="loading" msgid="2526615755685950317">"لوڈ ہو رہا ہے…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"انضمام پیشرفت میں ہے"</string>
diff --git a/apk/res/values-uz/strings.xml b/apk/res/values-uz/strings.xml
index 44f69ed..b6e19e4 100644
--- a/apk/res/values-uz/strings.xml
+++ b/apk/res/values-uz/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Bunga faol vaqt, mashq turi, aylanishlar, takrorlar, seanslar yoki suzish zarbalari kabi axborotlar kiradi"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Bunga uyqu bosqichlari va seanslari kabi axborotlar kiradi"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Barcha kiritilgan axborotlar"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"oʻzgartirish"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Bu maʼlumotlarni oʻchirib tashlash"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"salomatlik axborotiga kirish"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"mashq yoʻnalishi"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Mashq yoʻnalishini yozing"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Mashq yoʻnalishini oʻqish"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Barcha mashq marshrutlarini oʻqish"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Masofa"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"masofa"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Masofani oʻqish"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"dam olishdagi yurak urishi"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Dam olishdagi yurak urishini oʻqish"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Dam olishdagi yurak urishini yozish"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Tana harorati"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"tana harorati"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Tana haroratini oʻqish uchun ruxsat"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Tana harorati haqida maʼlumotlarni yozish"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ilovasiga oʻqish uchun ruxsat bering"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"“<xliff:g id="APP_NAME">%1$s</xliff:g>” ilovasiga yozish uchun ruxsat bering"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Bekor qilish"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Health Connect maʼlumotlari oʻchirib tashlanmoqda"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Health Connect maʼlumotlari oʻchirib tashlanmoqda"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Maʼlumotlarni oʻchirish"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Maʼlumot qaydlarini oʻchirib tashlash"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Qaydni oʻchirish"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> maʼlumot qaydlarini oʻchirib tashlash"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g> qaydini oʻchirish"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Jami: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 Vt}other{# Vt}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 vatt}other{# vatt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Pastga surish"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Boshiga olish"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Oxiriga olish"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Muhim ro\'yxatdan <xliff:g id="SELECTED_APP">%s</xliff:g> ilovasini olish tugmasi"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Qayta tartiblash uchun ikki marta bosing va suring"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"fitnes, salomatlik"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"ruxsatlar"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, salomatlik axboroti, salomatlik turkumlari, maʼlumotlarga kirish, faoliyat, jismoniy koʻrsatkichlar, davr kuzatuvi, ovqatlanish, uyqu, koʻrsatkichlar"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Faqat mashq marshrutiga siz ruxsat bergan ilovalar"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Ruxsatni qanday boshqarishim mumkin?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Mashq marshrutlariga ilova ruxsatlarini Health Connect sozlamalari orqali boshqarishingiz mumkin."</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Orqaga"</string>
     <string name="loading" msgid="2526615755685950317">"Yuklanmoqda…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Integratsiya davom etmoqda"</string>
diff --git a/apk/res/values-vi/strings.xml b/apk/res/values-vi/strings.xml
index 9071471..487c8b3 100644
--- a/apk/res/values-vi/strings.xml
+++ b/apk/res/values-vi/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Dữ liệu này bao gồm thông tin như thời gian hoạt động, loại bài tập, số vòng, số lần lặp lại, số phiên hoặc kiểu bơi"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Dữ liệu này bao gồm thông tin như các giai đoạn ngủ và giấc ngủ"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Xem tất cả các mục"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"thay đổi"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Xoá dữ liệu này"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"truy cập vào dữ liệu sức khoẻ của bạn"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"tuyến đường tập thể dục"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Ghi dữ liệu về tuyến đường tập thể dục"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Đọc dữ liệu về lộ trình tập luyện"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Đọc tất cả tuyến đường tập thể dục"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Quãng đường"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"quãng đường"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Đọc dữ liệu về quãng đường"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"nhịp tim lúc nghỉ ngơi"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Đọc dữ liệu về nhịp tim lúc nghỉ ngơi"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Ghi dữ liệu về nhịp tim lúc nghỉ ngơi"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Nhiệt độ trên da"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"nhiệt độ trên da"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Đọc dữ liệu về nhiệt độ trên da"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Ghi dữ liệu về nhiệt độ trên da"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Cho phép \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" đọc dữ liệu"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Cho phép \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ghi dữ liệu"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Huỷ"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Đang xoá dữ liệu trong Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Đang xoá dữ liệu trong Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Xoá dữ liệu"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Xoá mục dữ liệu"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Xoá mục"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Xoá mục dữ liệu <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Xoá mục <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Tổng: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 watt}other{# watt}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Chuyển xuống"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Chuyển lên trên cùng"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Chuyển xuống dưới cùng"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Nút để xoá <xliff:g id="SELECTED_APP">%s</xliff:g> khỏi danh sách ưu tiên"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Nhấn đúp và kéo để sắp xếp lại"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"thể chất, sức khoẻ"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"quyền"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, dữ liệu sức khoẻ, danh mục liên quan đến sức khoẻ, truy cập dữ liệu, hoạt động, số đo cơ thể, theo dõi chu kỳ kinh nguyệt, dinh dưỡng, giấc ngủ, chỉ số sức khoẻ"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Chỉ những ứng dụng bạn cho phép truy cập vào tuyến đường tập thể dục của mình"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Làm cách nào để quản lý quyền truy cập?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Bạn có thể quản lý quyền truy cập của ứng dụng vào các tuyến đường tập thể dục trong phần cài đặt của Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Quay lại"</string>
     <string name="loading" msgid="2526615755685950317">"Đang tải…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Đang trong quá trình tích hợp"</string>
diff --git a/apk/res/values-zh-rCN/strings.xml b/apk/res/values-zh-rCN/strings.xml
index eb3557e..49e6a1a 100644
--- a/apk/res/values-zh-rCN/strings.xml
+++ b/apk/res/values-zh-rCN/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"此数据包含运动时间、锻炼类型、趟数、重复次数、时段或游泳动作等信息"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"此数据包含睡眠阶段和睡眠时段等信息"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"查看所有条目"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"更改"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"删除此数据"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"健康数据共享"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"访问您的健康数据"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"锻炼路线"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"写入锻炼路线"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"读取锻炼路线"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"读取所有锻炼路线"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"距离"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"距离"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"读取距离数据"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"静息心率"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"读取静息心率数据"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"写入静息心率数据"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"体表温度"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"体表温度"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"读取体表温度"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"写入体表温度"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”读取"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”写入"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"取消"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"正在删除健康数据共享中的数据"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"正在删除健康数据共享中的数据"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"数据删除"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"删除数据记录"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"删除条目"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"删除数据条目“<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>”"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"删除条目“<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>”"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"总计:<xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 瓦特}other{# 瓦特}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"下移"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"移至顶部"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"移至底部"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"按钮,用于从优先级列表中移除“<xliff:g id="SELECTED_APP">%s</xliff:g>”"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"点按两次并拖动即可重新排序"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"健身, 健康, fitness, wellness"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"权限"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"健康数据共享, 健康数据, 健康类别, 数据访问权限, 活动, 身体测量数据, 经期记录, 营养, 睡眠, 生命体征, health connect, health data, health categories, data access, activity, body measurements, cycle tracking, nutrition, sleep, vitals"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"只有您授予了相应权限的应用才能访问您的锻炼路线"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"如何管理访问权限?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"您可以在健康数据共享设置中管理应用对锻炼路线的访问权限"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"返回"</string>
     <string name="loading" msgid="2526615755685950317">"正在加载…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"集成正在进行中"</string>
diff --git a/apk/res/values-zh-rHK/strings.xml b/apk/res/values-zh-rHK/strings.xml
index e0d4dd4..3955022 100644
--- a/apk/res/values-zh-rHK/strings.xml
+++ b/apk/res/values-zh-rHK/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"此資料包括活動時間、運動類型、圈數、重複次數、時段、泳式等資料"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"此資料包括睡眠階段和睡眠時段"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"查看所有資料"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"變更"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"刪除此資料"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"存取你的健康資料"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"運動路線"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"寫入運動路線"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"讀取運動路線"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"朗讀所有運動路線"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"距離"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"距離"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"讀取距離資料"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"靜止心率"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"讀取靜止心率資料"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"寫入靜止心率資料"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"皮膚溫度"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"皮膚溫度"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"讀取皮膚溫度"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"寫入皮膚溫度"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」讀取"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」寫入"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"取消"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"正在刪除 Health Connect 資料"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"正在刪除 Health Connect 資料"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"資料刪除"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"刪除資料項目"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"刪除項目"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"刪除資料項目:<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"刪除項目:<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"總計:<xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 瓦特}other{# 瓦特}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 瓦特}other{# 瓦特}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"向下移"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"移到頂部"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"移到底部"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"㩒呢個制就可以喺優先清單度移除「<xliff:g id="SELECTED_APP">%s</xliff:g>」"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"㩒兩下然後拖動就可以重新排序"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"健身, 健康"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"權限"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"health connect, 健康資料, 健康類型, 資料存取權, 活動, 身體測量數據, 經期追蹤, 營養, 睡眠, 健康數據"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"只有你允許的應用程式能存取運動路線"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"如何管理存取權?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"你可在 Health Connect 設定中管理應用程式的運動路線存取權"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"返回"</string>
     <string name="loading" msgid="2526615755685950317">"正在載入…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"整合中"</string>
diff --git a/apk/res/values-zh-rTW/strings.xml b/apk/res/values-zh-rTW/strings.xml
index 997f4d7..83392b8 100644
--- a/apk/res/values-zh-rTW/strings.xml
+++ b/apk/res/values-zh-rTW/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"這類資料包括活動時間、運動類型、圈數、重複次數、時段或泳姿等資訊"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"這類資料包括睡眠階段和睡眠時段"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"查看所有資料"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"變更"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"刪除這類資料"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"健康資料同步"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"存取你的健康資料"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"運動路線"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"寫入運動路線"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"讀取運動路線"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"讀取所有運動路線"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"距離"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"距離"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"讀取距離資料"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"靜止心率"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"讀取靜止心率資料"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"寫入靜止心率資料"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"皮膚溫度"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"皮膚溫度"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"讀取皮膚溫度"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"寫入皮膚溫度"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」讀取"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」寫入"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"取消"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"正在刪除「健康資料同步」資料"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"正在刪除「健康資料同步」資料"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"資料刪除"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"刪除資料項目"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"刪除項目"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"刪除「<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>」資料項目"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"刪除「<xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>」項目"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"總計:<xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 瓦特}other{# 瓦特}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{1 瓦特}other{# 瓦特}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"向下移"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"移至頂端"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"移至底部"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"點選這個按鈕可從優先清單移除「<xliff:g id="SELECTED_APP">%s</xliff:g>」"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"輕觸兩下並拖曳即可調整順序"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"健身, 健康"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"權限"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"健康資料同步, 健康資料, 健康類別, 資料存取, 活動, 身體測量資料, 經期追蹤, 營養, 睡眠, 生命徵象"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"只有你允許的應用程式能存取運動路線"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"如何管理存取權?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"你可以在「健康資料同步」設定中管理應用程式的運動路線存取權"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"返回"</string>
     <string name="loading" msgid="2526615755685950317">"載入中…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"整合中"</string>
diff --git a/apk/res/values-zu/strings.xml b/apk/res/values-zu/strings.xml
index 2b6e8c1..aaf7960 100644
--- a/apk/res/values-zu/strings.xml
+++ b/apk/res/values-zu/strings.xml
@@ -75,6 +75,7 @@
     <string name="data_access_exercise_description" msgid="6868583522699443570">"Le datha ihlanganisa ulwazi olufana nesikhathi sokusebenza, uhlobo lokujima, amalephu, ukuphindaphinda, amaseshini, noma ama-stroke okubhukuda"</string>
     <string name="data_access_sleep_description" msgid="74293126050011153">"Le datha ihlanganisa ulwazi olufana nezigaba zokulala namaseshini okulala"</string>
     <string name="all_entries_button" msgid="5109091107239135235">"Bona konke okufakiwe"</string>
+    <string name="selected_date_view_action_description" msgid="6237240886988225664">"shintsha"</string>
     <string name="delete_permission_type_data_button" msgid="2270819954943391797">"Sula le datha"</string>
     <string name="permgrouplab_health" msgid="468961137496587966">"I-Health Connect"</string>
     <string name="permgroupdesc_health" msgid="252080476917407273">"finyelela idatha yakho yezempilo"</string>
@@ -95,7 +96,8 @@
     <string name="exercise_route_lowercase_label" msgid="1691912731748211252">"umzila wokuzivocavoca"</string>
     <string name="exercise_route_write_content_description" msgid="257809942953352611">"Bhala umzila wokuzivocavoca"</string>
     <string name="exercise_route_read_content_description" msgid="8394028537674463440">"Funda indlela yokujima"</string>
-    <string name="exercise_routes_all_read_content_description" msgid="5799035808926978381">"Funda yonke imizila yokujima"</string>
+    <!-- no translation found for exercise_routes_read_content_description (9001690141308870706) -->
+    <skip />
     <string name="distance_uppercase_label" msgid="1420705424462077174">"Ibanga"</string>
     <string name="distance_lowercase_label" msgid="2287154001209381379">"ibanga"</string>
     <string name="distance_read_content_description" msgid="8787235642020285789">"Funda ibanga"</string>
@@ -240,6 +242,10 @@
     <string name="resting_heart_rate_lowercase_label" msgid="4533866739695973169">"izinga lokushaya kwenhliziyo kokuphumula"</string>
     <string name="resting_heart_rate_read_content_description" msgid="1068160055773401020">"Funda izinga lokushaya kwenhliziyo lapho uphumule"</string>
     <string name="resting_heart_rate_write_content_description" msgid="8848198128082739995">"Bhala izinga lokushaya kwenhliziyo lapho uphumule"</string>
+    <string name="skin_temperature_uppercase_label" msgid="4880306019368461268">"Izinga lokushisa lesikhumba"</string>
+    <string name="skin_temperature_lowercase_label" msgid="7456421703641980581">"izinga lokushisa lesikhumba"</string>
+    <string name="skin_temperature_read_content_description" msgid="1896127631429717621">"Funda izinga lokushisa lesikhumba"</string>
+    <string name="skin_temperature_write_content_description" msgid="6448587289116206085">"Bhala izinga lokushisa lesikhumba"</string>
     <string name="read_permission_category" msgid="6002099618259628632">"Vumela i-“<xliff:g id="APP_NAME">%1$s</xliff:g>” ukuba ifunde"</string>
     <string name="write_permission_category" msgid="1529702804865008111">"Vumela i-“<xliff:g id="APP_NAME">%1$s</xliff:g>” ukuba ibhale"</string>
     <string name="request_permissions_cancel" msgid="1787483997235365393">"Khansela"</string>
@@ -347,8 +353,8 @@
     <string name="delete_data_notification_title" msgid="7740230240986343347">"Isula idatha ye-Health Connect"</string>
     <string name="delete_data_notification_ticker_text" msgid="2604051567679235822">"Isula idatha ye-Health Connect"</string>
     <string name="delete_data_notification_channel_name" msgid="4499713830012802095">"Ukusulwa kwedatha"</string>
-    <string name="data_point_action_content_description" msgid="7872439279343967754">"Sula okufakiwe kwedatha"</string>
-    <string name="delete_data_point" msgid="4234569507133768630">"Susa okufakwayo"</string>
+    <string name="data_point_action_content_description" msgid="6881048311770784455">"Sula okufakiwe kwedatha okuthi <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
+    <string name="delete_data_point" msgid="1004049578454616738">"Susa okufakwayo okuthi <xliff:g id="ENTRY_TO_DELETE">%s</xliff:g>"</string>
     <string name="aggregation_total" msgid="5641333638662325184">"Isamba: <xliff:g id="TOTAL_VALUE">%s</xliff:g>"</string>
     <string name="watt_format" msgid="8500953817369623803">"{value,plural, =1{1 W}one{# W}other{# W}}"</string>
     <string name="watt_format_long" msgid="7107446926499116109">"{value,plural, =1{i-watt e-1}one{ama-watt angu-#}other{ama-watt angu-#}}"</string>
@@ -710,6 +716,10 @@
     <string name="action_drag_label_move_down" msgid="3448000958912947588">"Yehlisa"</string>
     <string name="action_drag_label_move_top" msgid="5114033774108663548">"Hambise uyise phezulu"</string>
     <string name="action_drag_label_move_bottom" msgid="3117764196696569512">"Yisa phansi"</string>
+    <!-- no translation found for reorder_button_content_description (2685032520710743533) -->
+    <skip />
+    <string name="remove_button_content_description" msgid="6170490900032612048">"Inkinobho yokususa i-<xliff:g id="SELECTED_APP">%s</xliff:g> kuhlu lokubalulekile"</string>
+    <string name="reorder_button_action_description" msgid="5197462036756192214">"Thepha kabili bese uyahudula ukuze uhlele kabusha"</string>
     <string name="search_keywords_home" msgid="5386515593026555327">"ukufaneleka, impilo enhle"</string>
     <string name="search_keywords_permissions" msgid="7821010295153350533">"izimvume"</string>
     <string name="search_keywords_data" msgid="5359602744325490523">"ukuxhumana kwezempilo, idatha yezempilo, izigaba zezempilo, ukufinyelela idatha, umsebenzi, izilinganiso zomzimba, ukulandelela umjikelezo, umsoco, ukulala, okubalulekile"</string>
@@ -726,6 +736,12 @@
     <string name="request_route_info_who_can_see_data_summary" msgid="2439434359808367150">"Ama-app owavumela ukuthi afinyelele imizila yakho yokujima kuphela"</string>
     <string name="request_route_info_access_management_title" msgid="3222594923675464852">"Ngingakuphatha kanjani ukufinyelela?"</string>
     <string name="request_route_info_access_management_summary" msgid="2606548838292829495">"Ungaphatha ukufinyelela kwe-app emizileni yokujima kumasethingi we-Health Connect"</string>
+    <!-- no translation found for request_route_allow (4427372851821847274) -->
+    <skip />
+    <!-- no translation found for request_route_allow_all (314830698958736916) -->
+    <skip />
+    <!-- no translation found for request_route_dont_allow (1186236234664957228) -->
+    <skip />
     <string name="back_button" msgid="780519527385993407">"Emuva"</string>
     <string name="loading" msgid="2526615755685950317">"Iyalayisha…"</string>
     <string name="migration_in_progress_screen_title" msgid="6564515269988205874">"Ukuhlanganisa kuyaqhubeka"</string>
diff --git a/apk/res/values/strings.xml b/apk/res/values/strings.xml
index 0eab6d7..ac5369c 100644
--- a/apk/res/values/strings.xml
+++ b/apk/res/values/strings.xml
@@ -97,6 +97,7 @@
     <string name="data_access_exercise_description" description="Description of data access for the exercise data type [CHAR_LIMIT=NONE]">This data includes information like active time, exercise type, laps, repetitions, sessions, or swimming strokes</string>
     <string name="data_access_sleep_description" description="Description of data access for the sleep data type [CHAR_LIMIT=NONE]">This data includes information like sleep stages and sleep sessions</string>
     <string name="all_entries_button" description="Label for a button that opens the Data entries page. [CHAR_LIMIT=50]">See all entries</string>
+    <string name="selected_date_view_action_description" description="Action description of a selected date view for accessibility [CHAR LIMIT=NONE]">change</string>
     <string name="delete_permission_type_data_button" description="Label for a button that allows deleting all data points from a given health permission type. [CHAR_LIMIT=50]">Delete this data</string>
     <!--endregion-->
 
@@ -134,7 +135,7 @@
     <string name="exercise_route_lowercase_label" description="Lowercase label used to show the user's exercise route [CHAR_LIMIT=50]">exercise route</string>
     <string name="exercise_route_write_content_description" description="Content description for switch that enables permissions for writing the user's exercise route [CHAR_LIMIT=NONE]">Write exercise route</string>
     <string name="exercise_route_read_content_description" description="Content description for switch that enables permissions for reading the user's exercise route [CHAR_LIMIT=NONE]">Read exercise route</string>
-    <string name="exercise_routes_all_read_content_description" description="Content description for switch that enables permissions for reading all user's exercise routes [CHAR_LIMIT=NONE]">Read all exercise routes</string>
+    <string name="exercise_routes_read_content_description" description="Content description for switch that enables permissions for reading user's exercise routes [CHAR_LIMIT=NONE]">Read exercise routes</string>
 
     <string name="distance_uppercase_label" description="Uppercase label used to show the user's distance data [CHAR_LIMIT=50]">Distance</string>
     <string name="distance_lowercase_label" description="Lowercase label used to show the user's distance data [CHAR_LIMIT=50]">distance</string>
@@ -326,6 +327,11 @@
     <string name="resting_heart_rate_lowercase_label" description="Lowercase label used to show the user's resting heart rate data [CHAR_LIMIT=50]">resting heart rate</string>
     <string name="resting_heart_rate_read_content_description" description="Content description for switch that enables permissions for reading the user's resting heart rate data [CHAR_LIMIT=NONE]">Read resting heart rate</string>
     <string name="resting_heart_rate_write_content_description" description="Content description for switch that enables permissions for writing the user's resting heart rate data [CHAR_LIMIT=NONE]">Write resting heart rate</string>
+
+    <string name="skin_temperature_uppercase_label" description="Uppercase label used to show the user's skin temperature data [CHAR_LIMIT=50]">Skin temperature</string>
+    <string name="skin_temperature_lowercase_label" description="Lowercase label used to show the user's skin temperature data [CHAR_LIMIT=50]">skin temperature</string>
+    <string name="skin_temperature_read_content_description" description="Content description for switch that enables permissions for reading the user's skin temperature data [CHAR_LIMIT=NONE]">Read skin temperature</string>
+    <string name="skin_temperature_write_content_description" description="Content description for switch that enables permissions for writing the user's skin temperature data [CHAR_LIMIT=NONE]">Write skin temperature</string>
     <!--endregion-->
     <!--endregion-->
 
@@ -479,8 +485,8 @@
     <!-- region Data entries -->
     <string name="data_entry_header_with_source_app" translatable="false"><xliff:g example="14:41" id="time">%1$s</xliff:g> • <xliff:g example="Run tracker" id="app_data">%2$s</xliff:g></string>
     <string name="data_entry_header_without_source_app" translatable="false"><xliff:g example="14:41" id="time">%1$s</xliff:g></string>
-    <string name="data_point_action_content_description" description="Content description for the menu button of an individual data entry [CHAR LIMIT=NONE]">Delete data entry</string>
-    <string name="delete_data_point" description="Menu option for deleting an individual data entry [CHAR LIMIT=50]">Delete entry</string>
+    <string name="data_point_action_content_description" description="Content description for the menu button of an individual data entry [CHAR LIMIT=NONE]">Delete data entry <xliff:g id="entry_to_delete" example="1000 steps">%s</xliff:g></string>
+    <string name="delete_data_point" description="Menu option for deleting an individual data entry [CHAR LIMIT=50]">Delete entry <xliff:g id="entry_to_delete" example="1000 steps">%s</xliff:g></string>
     <string name="aggregation_total" description="Description before the total value. For instance, Total: 1000 steps. [CHAR LIMIT=50]">Total: <xliff:g id="total_value" example="1000 steps">%s</xliff:g></string>
 
     <string name="watt_format" description="Power value with unit. [ICU SYNTAX][CHAR LIMIT=80]">{value, plural, =1 {1 W} other {# W}}</string>
@@ -950,8 +956,9 @@
     <string name="action_drag_label_move_down" description="Label for an accessibility action that moves an app down in the ordered app priority list [CHAR LIMIT=50]">Move down</string>
     <string name="action_drag_label_move_top" description="Label for an accessibility action that moves an app to the top of the ordered app priority list [CHAR LIMIT=50]">Move to top</string>
     <string name="action_drag_label_move_bottom" description="Label for an accessibility action that moves an app to the bottom of the ordered app priority list [CHAR LIMIT=50]">Move to bottom</string>
-    <string name="reorder_button_content_description" description="Content description of a button for accessibility that is used to reorder selected app in the app priority list [CHAR LIMIT=50]">Button to reorder <xliff:g id="selected_app" example="Test app">%s</xliff:g> in the priority list</string>
-    <string name="remove_button_content_description" description="Content description of a button for accessibility that is used to remove selected app from the app priority list [CHAR LIMIT=50]">Button to remove <xliff:g id="selected_app" example="Test app">%s</xliff:g> from the priority list</string>
+    <string name="reorder_button_content_description" description="Content description of a button for accessibility that is used to reorder selected app in the app priority list [CHAR LIMIT=NONE]">Button to drag and reorder <xliff:g id="selected_app" example="Test app">%s</xliff:g> in the priority list</string>
+    <string name="remove_button_content_description" description="Content description of a button for accessibility that is used to remove selected app from the app priority list [CHAR LIMIT=NONE]">Button to remove <xliff:g id="selected_app" example="Test app">%s</xliff:g> from the priority list</string>
+    <string name="reorder_button_action_description" description="Action description of a button for accessibility that is used to reorder selected app from the app priority list [CHAR LIMIT=NONE]">Double tap and drag to reorder</string>
     <!--  endregion-->
 
     <!--  region Search Indexable-->
@@ -982,6 +989,9 @@
     <string name="request_route_info_who_can_see_data_summary" description="Summary of the section explaining in more detail what it means to give permissions to an app to access a route for an exercise session and who will have access to the data. [CHAR_LIMIT=NONE]">Only apps you allow to access your exercise routes</string>
     <string name="request_route_info_access_management_title" description="Title for the section explaining in more detail what it means to give permissions to an app to access a route for an exercise session and how to manage the access. [CHAR_LIMIT=NONE]">How can I manage access?</string>
     <string name="request_route_info_access_management_summary" description="Summary of the section explaining in more detail what it means to give permissions to an app to access a route for an exercise session and and how to manage the access. Note: Health Connect is the brand. [CHAR_LIMIT=NONE]">You can manage app access to exercise routes in Health&#160;Connect settings</string>
+    <string name="request_route_allow" description="Label for button in the route request dialog to allow an app access the requested exercise route [CHAR_LIMIT=30]">Allow this route</string>
+    <string name="request_route_allow_all" description="Label for button in the route request dialog to allow an app access all exercise routes from now on [CHAR_LIMIT=30]">Allow all routes</string>
+    <string name="request_route_dont_allow" description="Label for button in the route request dialog to deny an app access to the requested route [CHAR_LIMIT=20]">Don\'t allow</string>
     <string name="back_button" description="Label on the back button. [CHAR_LIMIT=20]">Back</string>
     <!--  endregion-->
 
diff --git a/apk/res/values/styles.xml b/apk/res/values/styles.xml
index 2dc7db0..adf6e66 100644
--- a/apk/res/values/styles.xml
+++ b/apk/res/values/styles.xml
@@ -206,7 +206,7 @@
     </style>
 
     <style name="Widget.HealthConnect.CalendarSpinner" parent="android:style/Widget.Material.Spinner">
-        <item name="android:background">@drawable/settingslib_spinner_background</item>
+        <item name="android:background">@drawable/spinner_background</item>
         <item name="android:popupBackground">@drawable/settingslib_spinner_dropdown_background
         </item>
         <item name="android:paddingStart">@dimen/spacing_normal</item>
diff --git a/apk/src/com/android/healthconnect/controller/data/entries/datenavigation/DateNavigationView.kt b/apk/src/com/android/healthconnect/controller/data/entries/datenavigation/DateNavigationView.kt
index 8cb1cec..0e457f3 100644
--- a/apk/src/com/android/healthconnect/controller/data/entries/datenavigation/DateNavigationView.kt
+++ b/apk/src/com/android/healthconnect/controller/data/entries/datenavigation/DateNavigationView.kt
@@ -18,10 +18,12 @@
 import android.content.Context
 import android.util.AttributeSet
 import android.view.View
+import android.view.accessibility.AccessibilityNodeInfo
 import android.widget.AdapterView
 import android.widget.ImageButton
 import android.widget.Spinner
 import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
 import com.android.healthconnect.controller.R
 import com.android.healthconnect.controller.data.entries.datenavigation.DateNavigationPeriod.PERIOD_DAY
 import com.android.healthconnect.controller.data.entries.datenavigation.DateNavigationPeriod.PERIOD_MONTH
@@ -145,6 +147,20 @@
                     updateDisplayedDates()
                 }
             }
+
+        datePickerSpinner.accessibilityDelegate =
+            object : AccessibilityDelegate() {
+                override fun onInitializeAccessibilityNodeInfo(
+                    host: View,
+                    info: AccessibilityNodeInfo
+                ) {
+                    super.onInitializeAccessibilityNodeInfo(host, info)
+                    info.addAction(
+                        AccessibilityNodeInfo.AccessibilityAction(
+                            AccessibilityNodeInfoCompat.ACTION_CLICK,
+                            context.getString(R.string.selected_date_view_action_description)))
+                }
+            }
     }
 
     private fun updateDisplayedDates() {
diff --git a/apk/src/com/android/healthconnect/controller/dataentries/DateNavigationView.kt b/apk/src/com/android/healthconnect/controller/dataentries/DateNavigationView.kt
index 811c113..d14f843 100644
--- a/apk/src/com/android/healthconnect/controller/dataentries/DateNavigationView.kt
+++ b/apk/src/com/android/healthconnect/controller/dataentries/DateNavigationView.kt
@@ -19,9 +19,11 @@
 import android.util.AttributeSet
 import android.view.View
 import android.view.accessibility.AccessibilityEvent
+import android.view.accessibility.AccessibilityNodeInfo
 import android.widget.ImageButton
 import android.widget.TextView
 import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat
 import com.android.healthconnect.controller.R
 import com.android.healthconnect.controller.utils.DatePickerFactory
 import com.android.healthconnect.controller.utils.LocalDateTimeFormatter
@@ -119,6 +121,19 @@
             }
             datePickerDialog.show()
         }
+        selectedDateView.accessibilityDelegate =
+            object : AccessibilityDelegate() {
+                override fun onInitializeAccessibilityNodeInfo(
+                    host: View,
+                    info: AccessibilityNodeInfo
+                ) {
+                    super.onInitializeAccessibilityNodeInfo(host, info)
+                    info.addAction(
+                        AccessibilityNodeInfo.AccessibilityAction(
+                            AccessibilityNodeInfoCompat.ACTION_CLICK,
+                            context.getString(R.string.selected_date_view_action_description)))
+                }
+            }
     }
 
     private fun updateSelectedDate() {
diff --git a/apk/src/com/android/healthconnect/controller/dataentries/EntryItemViewBinder.kt b/apk/src/com/android/healthconnect/controller/dataentries/EntryItemViewBinder.kt
index 228750b..edb6381 100644
--- a/apk/src/com/android/healthconnect/controller/dataentries/EntryItemViewBinder.kt
+++ b/apk/src/com/android/healthconnect/controller/dataentries/EntryItemViewBinder.kt
@@ -54,6 +54,9 @@
         header.text = data.header
         header.contentDescription = data.headerA11y
 
+        deleteButton.contentDescription =
+            view.resources.getString(
+                R.string.data_point_action_content_description, data.headerA11y)
         deleteButton.setOnClickListener {
             logger.logInteraction(DataEntriesElement.DATA_ENTRY_DELETE_BUTTON)
             onDeleteEntryListener.onDeleteEntry(
diff --git a/apk/src/com/android/healthconnect/controller/dataentries/ExerciseSessionItemViewBinder.kt b/apk/src/com/android/healthconnect/controller/dataentries/ExerciseSessionItemViewBinder.kt
index b634aae..ec817f8 100644
--- a/apk/src/com/android/healthconnect/controller/dataentries/ExerciseSessionItemViewBinder.kt
+++ b/apk/src/com/android/healthconnect/controller/dataentries/ExerciseSessionItemViewBinder.kt
@@ -75,6 +75,9 @@
             mapView.setRoute(data.route)
         }
 
+        deleteButton.contentDescription =
+            view.resources.getString(
+                R.string.data_point_action_content_description, data.headerA11y)
         deleteButton.setOnClickListener {
             logger.logInteraction(DataEntriesElement.DATA_ENTRY_DELETE_BUTTON)
             onDeleteEntryClicked?.onDeleteEntry(data.uuid, data.dataType, index)
diff --git a/apk/src/com/android/healthconnect/controller/dataentries/SeriesDataItemViewBinder.kt b/apk/src/com/android/healthconnect/controller/dataentries/SeriesDataItemViewBinder.kt
index b484299..6473869 100644
--- a/apk/src/com/android/healthconnect/controller/dataentries/SeriesDataItemViewBinder.kt
+++ b/apk/src/com/android/healthconnect/controller/dataentries/SeriesDataItemViewBinder.kt
@@ -64,6 +64,9 @@
         deleteButton.isVisible = showSecondAction
         divider.isVisible = showSecondAction
 
+        deleteButton.contentDescription =
+            view.resources.getString(
+                R.string.data_point_action_content_description, data.headerA11y)
         deleteButton.setOnClickListener {
             logger.logInteraction(DataEntriesElement.DATA_ENTRY_DELETE_BUTTON)
             onDeleteEntryClicked?.onDeleteEntry(data.uuid, data.dataType, index)
diff --git a/apk/src/com/android/healthconnect/controller/dataentries/SleepSessionItemViewBinder.kt b/apk/src/com/android/healthconnect/controller/dataentries/SleepSessionItemViewBinder.kt
index c8df3cc..2c2119d 100644
--- a/apk/src/com/android/healthconnect/controller/dataentries/SleepSessionItemViewBinder.kt
+++ b/apk/src/com/android/healthconnect/controller/dataentries/SleepSessionItemViewBinder.kt
@@ -71,6 +71,9 @@
             logger.logInteraction(DataEntriesElement.DATA_ENTRY_DELETE_BUTTON)
             onDeleteEntryListenerClicked?.onDeleteEntry(data.uuid, data.dataType, index)
         }
+        deleteButton.contentDescription =
+            view.resources.getString(
+                R.string.data_point_action_content_description, data.headerA11y)
         if (showSecondAction) {
             container.setOnClickListener {
                 logger.logInteraction(DataEntriesElement.SLEEP_SESSION_ENTRY_BUTTON)
diff --git a/apk/src/com/android/healthconnect/controller/datasources/DataSourcesFragment.kt b/apk/src/com/android/healthconnect/controller/datasources/DataSourcesFragment.kt
index 4c6f2b5..ed59b99 100644
--- a/apk/src/com/android/healthconnect/controller/datasources/DataSourcesFragment.kt
+++ b/apk/src/com/android/healthconnect/controller/datasources/DataSourcesFragment.kt
@@ -18,6 +18,7 @@
 import android.view.MenuItem
 import android.view.View
 import android.widget.AdapterView
+import androidx.annotation.VisibleForTesting
 import androidx.core.os.bundleOf
 import androidx.fragment.app.activityViewModels
 import androidx.navigation.fragment.findNavController
@@ -217,7 +218,8 @@
         }
     }
 
-    private fun editPriorityList() {
+    @VisibleForTesting
+    fun editPriorityList() {
         isEditMode = true
         updateMenu(shouldShowEditButton = false)
         appSourcesPreferenceGroup?.removePreferenceRecursively(ADD_AN_APP_PREFERENCE_KEY)
@@ -396,6 +398,7 @@
 
                     val currentCategory = dataSourcesCategories[position]
                     currentCategorySelection = dataSourcesCategories[position]
+                    exitEditMode()
 
                     // Reload the data sources information when a new category has been selected
                     dataSourcesViewModel.loadData(currentCategory)
diff --git a/apk/src/com/android/healthconnect/controller/datasources/appsources/AppSourcesAdapter.kt b/apk/src/com/android/healthconnect/controller/datasources/appsources/AppSourcesAdapter.kt
index 1d56a81..3941be7 100644
--- a/apk/src/com/android/healthconnect/controller/datasources/appsources/AppSourcesAdapter.kt
+++ b/apk/src/com/android/healthconnect/controller/datasources/appsources/AppSourcesAdapter.kt
@@ -135,6 +135,8 @@
         itemView: View,
         private val onItemDragStartedListener: ItemTouchHelper?
     ) : RecyclerView.ViewHolder(itemView) {
+        private val EDIT_MODE_TAG = "edit_mode"
+        private val DRAG_MODE_TAG = "drag_mode"
         private val appPositionView: TextView
         private val appNameView: TextView
         private val appSourceSummary: TextView
@@ -181,6 +183,7 @@
                 AttributeResolver.getDrawable(itemView.context, R.attr.closeIcon)
             actionIconBackground.contentDescription =
                 context.getString(R.string.remove_button_content_description, appNameView.text)
+            actionIconBackground.tag = EDIT_MODE_TAG
             actionView.setOnTouchListener(null)
             actionView.setOnClickListener {
                 logger.logInteraction(DataSourcesElement.REMOVE_APP_SOURCE_BUTTON)
@@ -213,6 +216,7 @@
             } else {
                 actionIconBackground.background =
                     AttributeResolver.getDrawable(itemView.context, R.attr.priorityItemDragIcon)
+                actionIconBackground.tag = DRAG_MODE_TAG
                 actionView.setOnClickListener(null)
                 actionView.setOnTouchListener { _, event ->
                     logger.logInteraction(DataSourcesElement.REORDER_APP_SOURCE_BUTTON)
diff --git a/apk/src/com/android/healthconnect/controller/datasources/appsources/AppSourcesPreference.kt b/apk/src/com/android/healthconnect/controller/datasources/appsources/AppSourcesPreference.kt
index 453dd3a..87f81b7 100644
--- a/apk/src/com/android/healthconnect/controller/datasources/appsources/AppSourcesPreference.kt
+++ b/apk/src/com/android/healthconnect/controller/datasources/appsources/AppSourcesPreference.kt
@@ -51,6 +51,7 @@
         priorityList = dataSourcesViewModel.getEditedPriorityList()
         potentialAppSourcesList = dataSourcesViewModel.getEditedPotentialAppSources()
         priorityListView = holder.findViewById(R.id.linear_layout_recycle_view) as RecyclerView
+        priorityListView.isNestedScrollingEnabled = false
 
         adapter =
             AppSourcesAdapter(
diff --git a/apk/src/com/android/healthconnect/controller/deletion/DeletionFragment.kt b/apk/src/com/android/healthconnect/controller/deletion/DeletionFragment.kt
index 593f862..a541450 100644
--- a/apk/src/com/android/healthconnect/controller/deletion/DeletionFragment.kt
+++ b/apk/src/com/android/healthconnect/controller/deletion/DeletionFragment.kt
@@ -56,6 +56,7 @@
 class DeletionFragment : Hilt_DeletionFragment() {
 
     private val viewModel: DeletionViewModel by activityViewModels()
+    private var progressDialogFragment: ProgressDialogFragment? = null
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
@@ -164,8 +165,11 @@
     }
 
     private fun showProgressDialogFragment() {
-        ProgressDialogFragment(titleRes = R.string.delete_progress_indicator)
-            .show(childFragmentManager, ProgressDialogFragment.TAG)
+        if (progressDialogFragment == null) {
+            progressDialogFragment =
+                ProgressDialogFragment(titleRes = R.string.delete_progress_indicator)
+        }
+        progressDialogFragment?.show(childFragmentManager, ProgressDialogFragment.TAG)
     }
 
     private fun showSuccessDialogFragment() {
@@ -190,8 +194,8 @@
     }
 
     private fun hideProgressDialog() {
-        (childFragmentManager.findFragmentByTag(ProgressDialogFragment.TAG)
-                as ProgressDialogFragment?)
-            ?.dismiss()
+        if (progressDialogFragment != null) {
+            progressDialogFragment?.dismiss()
+        }
     }
 }
diff --git a/apk/src/com/android/healthconnect/controller/home/HomeFragment.kt b/apk/src/com/android/healthconnect/controller/home/HomeFragment.kt
index 5bc280a..3500d39 100644
--- a/apk/src/com/android/healthconnect/controller/home/HomeFragment.kt
+++ b/apk/src/com/android/healthconnect/controller/home/HomeFragment.kt
@@ -69,8 +69,7 @@
         this.setPageName(PageName.HOME_PAGE)
     }
 
-    @Inject
-    lateinit var featureUtils: FeatureUtils
+    @Inject lateinit var featureUtils: FeatureUtils
 
     private val recentAccessViewModel: RecentAccessViewModel by viewModels()
     private val homeFragmentViewModel: HomeFragmentViewModel by viewModels()
@@ -109,7 +108,8 @@
             true
         }
 
-        if (featureUtils.isNewAppPriorityEnabled() || featureUtils.isNewInformationArchitectureEnabled()) {
+        if (featureUtils.isNewAppPriorityEnabled() ||
+            featureUtils.isNewInformationArchitectureEnabled()) {
             mManageDataPreference?.logName = HomePageElement.MANAGE_DATA_BUTTON
             mManageDataPreference?.setOnPreferenceClickListener {
                 findNavController().navigate(R.id.action_homeFragment_to_manageDataFragment)
@@ -261,7 +261,9 @@
 
         if (recentAppsList.isEmpty()) {
             mRecentAccessPreference?.addPreference(
-                Preference(requireContext()).also { it.setSummary(R.string.no_recent_access) })
+                Preference(requireContext())
+                    .also { it.setSummary(R.string.no_recent_access) }
+                    .also { it.isSelectable = false })
         } else {
             recentAppsList.forEach { recentApp ->
                 val newRecentAccessPreference =
diff --git a/apk/src/com/android/healthconnect/controller/navigation/DestinationChangedListener.kt b/apk/src/com/android/healthconnect/controller/navigation/DestinationChangedListener.kt
index c7ae47f..1ced68d 100644
--- a/apk/src/com/android/healthconnect/controller/navigation/DestinationChangedListener.kt
+++ b/apk/src/com/android/healthconnect/controller/navigation/DestinationChangedListener.kt
@@ -29,6 +29,9 @@
     ) {
         // Prevent header from being collapsed between fragments.
         activity.appBarLayout?.setExpanded(true)
+        activity.appBarLayout?.let {
+            activity.collapsingToolbarLayout?.setContentScrimColor(it.solidColor)
+        }
         activity.setTitle(destination.label)
     }
 }
diff --git a/apk/src/com/android/healthconnect/controller/permissions/connectedapps/ConnectedAppsFragment.kt b/apk/src/com/android/healthconnect/controller/permissions/connectedapps/ConnectedAppsFragment.kt
index eb88c6d..6c59a29 100644
--- a/apk/src/com/android/healthconnect/controller/permissions/connectedapps/ConnectedAppsFragment.kt
+++ b/apk/src/com/android/healthconnect/controller/permissions/connectedapps/ConnectedAppsFragment.kt
@@ -22,6 +22,7 @@
 import android.view.View
 import android.widget.Toast
 import androidx.annotation.StringRes
+import androidx.appcompat.app.AlertDialog
 import androidx.core.os.bundleOf
 import androidx.fragment.app.commitNow
 import androidx.fragment.app.viewModels
@@ -84,6 +85,7 @@
     @Inject lateinit var deviceInfoUtils: DeviceInfoUtils
     private val viewModel: ConnectedAppsViewModel by viewModels()
     private lateinit var searchMenuItem: MenuItem
+    private lateinit var removeAllAppsDialog: AlertDialog
 
     private val mTopIntro: TopIntroPreference? by lazy {
         preferenceScreen.findPreference(TOP_INTRO)
@@ -118,28 +120,31 @@
         }
     }
 
-    private fun openRemoveAllAppsAccessDialog(apps: List<ConnectedAppMetadata>) {
-        AlertDialogBuilder(this)
-            .setLogName(DisconnectAllAppsDialogElement.DISCONNECT_ALL_APPS_DIALOG_CONTAINER)
-            .setIcon(R.attr.disconnectAllIcon)
-            .setTitle(R.string.permissions_disconnect_all_dialog_title)
-            .setMessage(R.string.permissions_disconnect_all_dialog_message)
-            .setNeutralButton(
-                android.R.string.cancel,
-                DisconnectAllAppsDialogElement.DISCONNECT_ALL_APPS_DIALOG_CANCEL_BUTTON) { _, _ ->
-                    viewModel.setAlertDialogStatus(false)
-                }
-            .setPositiveButton(
-                R.string.permissions_disconnect_all_dialog_disconnect,
-                DisconnectAllAppsDialogElement.DISCONNECT_ALL_APPS_DIALOG_REMOVE_ALL_BUTTON) { _, _
-                    ->
-                    if (!viewModel.disconnectAllApps(apps)) {
-                        Toast.makeText(requireContext(), R.string.default_error, Toast.LENGTH_SHORT)
-                            .show()
+    private fun createRemoveAllAppsAccessDialog(apps: List<ConnectedAppMetadata>) {
+        removeAllAppsDialog =
+            AlertDialogBuilder(this)
+                .setLogName(DisconnectAllAppsDialogElement.DISCONNECT_ALL_APPS_DIALOG_CONTAINER)
+                .setIcon(R.attr.disconnectAllIcon)
+                .setTitle(R.string.permissions_disconnect_all_dialog_title)
+                .setMessage(R.string.permissions_disconnect_all_dialog_message)
+                .setNeutralButton(
+                    android.R.string.cancel,
+                    DisconnectAllAppsDialogElement.DISCONNECT_ALL_APPS_DIALOG_CANCEL_BUTTON) { _, _
+                        ->
+                        viewModel.setAlertDialogStatus(false)
                     }
-                }
-            .create()
-            .show()
+                .setPositiveButton(
+                    R.string.permissions_disconnect_all_dialog_disconnect,
+                    DisconnectAllAppsDialogElement.DISCONNECT_ALL_APPS_DIALOG_REMOVE_ALL_BUTTON) {
+                        _,
+                        _ ->
+                        if (!viewModel.disconnectAllApps(apps)) {
+                            Toast.makeText(
+                                    requireContext(), R.string.default_error, Toast.LENGTH_SHORT)
+                                .show()
+                        }
+                    }
+                .create()
     }
 
     override fun onResume() {
@@ -195,6 +200,7 @@
                 val notAllowedApps = connectedAppsGroup[DENIED].orEmpty()
                 val activeApps: MutableList<ConnectedAppMetadata> = allowedApps.toMutableList()
                 activeApps.addAll(notAllowedApps)
+                createRemoveAllAppsAccessDialog(activeApps)
 
                 mSettingsAndHelpCategory?.addPreference(
                     getRemoveAccessForAllAppsPreference().apply {
@@ -216,7 +222,11 @@
 
                 viewModel.alertDialogActive.observe(viewLifecycleOwner) { state ->
                     if (state) {
-                        openRemoveAllAppsAccessDialog(activeApps)
+                        removeAllAppsDialog.show()
+                    } else {
+                        if (removeAllAppsDialog.isShowing) {
+                            removeAllAppsDialog.dismiss()
+                        }
                     }
                 }
             }
diff --git a/apk/src/com/android/healthconnect/controller/recentaccess/RecentAccessFragment.kt b/apk/src/com/android/healthconnect/controller/recentaccess/RecentAccessFragment.kt
index 6d0ad5a..73f0be6 100644
--- a/apk/src/com/android/healthconnect/controller/recentaccess/RecentAccessFragment.kt
+++ b/apk/src/com/android/healthconnect/controller/recentaccess/RecentAccessFragment.kt
@@ -144,6 +144,7 @@
             mRecentAccessYesterdayPreferenceGroup?.isVisible = false
             mRecentAccessTodayPreferenceGroup?.isVisible = false
             mRecentAccessNoDataPreference?.isVisible = true
+            mRecentAccessNoDataPreference?.isSelectable = false
             fab.isVisible = false
         } else {
             // if the first entry is yesterday, we don't need the 'Today' section
diff --git a/apk/src/com/android/healthconnect/controller/route/ExerciseRouteViewModel.kt b/apk/src/com/android/healthconnect/controller/route/ExerciseRouteViewModel.kt
index b4c7b0a..946c716 100644
--- a/apk/src/com/android/healthconnect/controller/route/ExerciseRouteViewModel.kt
+++ b/apk/src/com/android/healthconnect/controller/route/ExerciseRouteViewModel.kt
@@ -15,16 +15,23 @@
  */
 package com.android.healthconnect.controller.route
 
+import android.content.Context
+import android.content.pm.PackageManager
 import android.health.connect.datatypes.ExerciseSessionRecord
 import android.util.Log
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.viewModelScope
+import com.android.healthconnect.controller.permissions.api.GetGrantedHealthPermissionsUseCase
+import com.android.healthconnect.controller.permissions.api.GetHealthPermissionsFlagsUseCase
+import com.android.healthconnect.controller.permissions.api.GrantHealthPermissionUseCase
+import com.android.healthconnect.controller.permissions.api.LoadAccessDateUseCase
 import com.android.healthconnect.controller.shared.app.AppInfoReader
 import com.android.healthconnect.controller.shared.app.AppMetadata
 import com.android.healthconnect.controller.shared.usecase.UseCaseResults
 import dagger.hilt.android.lifecycle.HiltViewModel
+import dagger.hilt.android.qualifiers.ApplicationContext
 import java.util.Objects
 import javax.inject.Inject
 import kotlinx.coroutines.launch
@@ -34,12 +41,20 @@
 class ExerciseRouteViewModel
 @Inject
 constructor(
+    @ApplicationContext private val context: Context,
     private val loadExerciseRouteUseCase: LoadExerciseRouteUseCase,
-    private val appInfoReader: AppInfoReader
+    private val getGrantedHealthPermissionsUseCase: GetGrantedHealthPermissionsUseCase,
+    private val getHealthPermissionsFlagsUseCase: GetHealthPermissionsFlagsUseCase,
+    private val grantHealthPermissionUseCase: GrantHealthPermissionUseCase,
+    private val loadAccessDateUseCase: LoadAccessDateUseCase,
+    private val appInfoReader: AppInfoReader,
 ) : ViewModel() {
 
     companion object {
         private const val TAG = "ExerciseRouteViewModel"
+        // TODO(b/300270771): use HealthPermissions.READ_EXERCISE_ROUTES when the API becomes
+        // unhidden.
+        private const val READ_EXERCISE_ROUTES = "android.permission.health.READ_EXERCISE_ROUTES"
     }
 
     private val _exerciseSession = MutableLiveData<SessionWithAttribution?>()
@@ -69,5 +84,41 @@
         }
     }
 
+    fun isReadRoutesPermissionGranted(packageName: String): Boolean {
+        val grantedPermissions = getGrantedHealthPermissionsUseCase(packageName)
+        return grantedPermissions.contains(READ_EXERCISE_ROUTES)
+    }
+
+    fun isReadRoutesPermissionUserFixed(packageName: String): Boolean {
+        val permission = READ_EXERCISE_ROUTES
+        val flags = getHealthPermissionsFlagsUseCase(packageName, listOf(permission))
+
+        return flags[permission]!!.and(PackageManager.FLAG_PERMISSION_USER_FIXED) != 0
+    }
+
+    fun isReadRoutesPermissionDeclared(packageName: String): Boolean {
+        return try {
+            val appInfo =
+                context.packageManager.getPackageInfo(
+                    packageName,
+                    PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS.toLong()))
+
+            return appInfo.requestedPermissions.contains(READ_EXERCISE_ROUTES)
+        } catch (e: PackageManager.NameNotFoundException) {
+            Log.e(TAG, "isPermissionDeclared error", e)
+            return false
+        }
+    }
+
+    fun grantReadRoutesPermission(packageName: String) {
+        grantHealthPermissionUseCase.invoke(packageName, READ_EXERCISE_ROUTES)
+    }
+
+    fun isSessionInaccessible(packageName: String, session: ExerciseSessionRecord): Boolean {
+        val accessLimit = loadAccessDateUseCase(packageName)
+
+        return session.startTime.isBefore(accessLimit)
+    }
+
     data class SessionWithAttribution(val session: ExerciseSessionRecord, val appInfo: AppMetadata)
 }
diff --git a/apk/src/com/android/healthconnect/controller/route/RouteRequestActivity.kt b/apk/src/com/android/healthconnect/controller/route/RouteRequestActivity.kt
index 9ff0815..066539e 100644
--- a/apk/src/com/android/healthconnect/controller/route/RouteRequestActivity.kt
+++ b/apk/src/com/android/healthconnect/controller/route/RouteRequestActivity.kt
@@ -19,8 +19,11 @@
 import android.content.Intent
 import android.health.connect.HealthConnectManager.EXTRA_EXERCISE_ROUTE
 import android.health.connect.HealthConnectManager.EXTRA_SESSION_ID
+import android.health.connect.datatypes.ExerciseRoute
 import android.os.Bundle
 import android.util.Log
+import android.view.View.GONE
+import android.view.View.VISIBLE
 import android.widget.Button
 import android.widget.LinearLayout
 import android.widget.TextView
@@ -55,14 +58,19 @@
     }
 
     @Inject lateinit var appInfoReader: AppInfoReader
+
     @Inject lateinit var featureUtils: FeatureUtils
 
     @VisibleForTesting var dialog: AlertDialog? = null
+
     @VisibleForTesting lateinit var infoDialog: AlertDialog
 
     private val viewModel: ExerciseRouteViewModel by viewModels()
     private val migrationViewModel: MigrationViewModel by viewModels()
 
+    private val sessionIdExtra: String?
+        get() = intent.getStringExtra(EXTRA_SESSION_ID)
+
     private var requester: String? = null
     private var migrationState = MigrationState.UNKNOWN
     private var sessionWithAttribution: SessionWithAttribution? = null
@@ -72,25 +80,29 @@
 
         if (!featureUtils.isExerciseRouteEnabled()) {
             Log.e(TAG, "Exercise routes not available, finishing.")
-            setResult(Activity.RESULT_CANCELED, Intent())
-            finish()
+            finishCancelled()
             return
         }
 
-        if (!intent.hasExtra(EXTRA_SESSION_ID) ||
-            intent.getStringExtra(EXTRA_SESSION_ID) == null ||
-            callingPackage == null) {
+        if (sessionIdExtra == null || callingPackage == null) {
             Log.e(TAG, "Invalid Intent Extras, finishing.")
-            setResult(Activity.RESULT_CANCELED, Intent())
-            finish()
+            finishCancelled()
             return
         }
 
-        viewModel.getExerciseWithRoute(intent.getStringExtra(EXTRA_SESSION_ID)!!)
-        runBlocking { requester = appInfoReader.getAppMetadata(callingPackage!!).appName }
+        val callingPackageName = callingPackage!!
+
+        if (!viewModel.isReadRoutesPermissionDeclared(callingPackageName)) {
+            Log.e(TAG, "Read permission not declared")
+            finishCancelled()
+            return
+        }
+
+        viewModel.getExerciseWithRoute(sessionIdExtra!!)
+        runBlocking { requester = appInfoReader.getAppMetadata(callingPackageName).appName }
         viewModel.exerciseSession.observe(this) { session ->
             this.sessionWithAttribution = session
-            setupRequestDialog(session)
+            setupRequestDialog(session, callingPackageName)
         }
 
         migrationViewModel.migrationState.observe(this) { migrationState ->
@@ -106,20 +118,39 @@
         }
     }
 
-    private fun setupRequestDialog(data: SessionWithAttribution?) {
-        if ((data == null) ||
-            (data.session?.route == null) ||
-            data.session?.route!!.routeLocations.isEmpty()) {
+    private fun setupRequestDialog(data: SessionWithAttribution?, callingPackage: String) {
+        if (data == null ||
+            data.session.route == null ||
+            data.session.route?.routeLocations.isNullOrEmpty()) {
             Log.e(TAG, "No route or empty route, finishing.")
-            val result = Intent()
-            result.putExtra(EXTRA_SESSION_ID, intent.getStringExtra(EXTRA_SESSION_ID))
-            setResult(Activity.RESULT_CANCELED, result)
-            finish()
+            finishCancelled()
             return
         }
 
-        val session = data.session!!
-        val sessionId = intent.getStringExtra(EXTRA_SESSION_ID)
+        val session = data.session
+        val route = session.route!!
+
+        if (session.metadata.dataOrigin.packageName == callingPackage) {
+            finishWithResult(route)
+            return
+        }
+
+        if (viewModel.isSessionInaccessible(callingPackage, session)) {
+            Log.i(TAG, "Requested exercise session is inaccessible.")
+            finishCancelled()
+            return
+        }
+
+        if (viewModel.isReadRoutesPermissionGranted(callingPackage)) {
+            finishWithResult(route)
+            return
+        }
+
+        if (viewModel.isReadRoutesPermissionUserFixed(callingPackage)) {
+            finishCancelled()
+            return
+        }
+
         val sessionDetails =
             applicationContext.getString(
                 R.string.date_owner_format,
@@ -145,18 +176,27 @@
         }
 
         view.findViewById<Button>(R.id.route_dont_allow_button).setOnClickListener {
-            val result = Intent()
-            result.putExtra(EXTRA_SESSION_ID, sessionId)
-            setResult(Activity.RESULT_CANCELED, result)
-            finish()
+            finishCancelled()
         }
 
+        val allowAllButton: Button = view.findViewById<Button>(R.id.route_allow_all_button)
+
+        allowAllButton.setOnClickListener {
+            viewModel.grantReadRoutesPermission(callingPackage)
+            finishWithResult(route)
+        }
+
+        val shouldShowAllowAllRoutesButton = featureUtils.isExerciseRouteReadAllEnabled()
+
+        allowAllButton.visibility =
+            if (shouldShowAllowAllRoutesButton) {
+                VISIBLE
+            } else {
+                GONE
+            }
+
         view.findViewById<Button>(R.id.route_allow_button).setOnClickListener {
-            val result = Intent()
-            result.putExtra(EXTRA_SESSION_ID, intent.getStringExtra(EXTRA_SESSION_ID))
-            result.putExtra(EXTRA_EXERCISE_ROUTE, session.route)
-            setResult(Activity.RESULT_OK, result)
-            finish()
+            finishWithResult(route)
         }
 
         dialog =
@@ -213,12 +253,7 @@
                     applicationContext.getString(
                         R.string.migration_pending_permissions_dialog_content, requester),
                     positiveButtonAction = { _, _ -> dialog?.show() },
-                    negativeButtonAction = { _, _ ->
-                        val result = Intent()
-                        result.putExtra(EXTRA_SESSION_ID, intent.getStringExtra(EXTRA_SESSION_ID))
-                        setResult(Activity.RESULT_CANCELED, result)
-                        finish()
-                    })
+                    negativeButtonAction = { _, _ -> finishCancelled() })
             }
             MigrationState.COMPLETE -> {
                 maybeShowWhatsNewDialog(this) { _, _ -> dialog?.show() }
@@ -234,4 +269,19 @@
         dialog?.dismiss()
         super.onDestroy()
     }
+
+    private fun finishWithResult(route: ExerciseRoute) {
+        val result = Intent()
+        result.putExtra(EXTRA_SESSION_ID, sessionIdExtra)
+        result.putExtra(EXTRA_EXERCISE_ROUTE, route)
+        setResult(Activity.RESULT_OK, result)
+        finish()
+    }
+
+    private fun finishCancelled() {
+        val result = Intent()
+        sessionIdExtra?.let { result.putExtra(EXTRA_SESSION_ID, it) }
+        setResult(Activity.RESULT_CANCELED, result)
+        finish()
+    }
 }
diff --git a/apk/src/com/android/healthconnect/controller/shared/HealthPermissionReader.kt b/apk/src/com/android/healthconnect/controller/shared/HealthPermissionReader.kt
index ee16299..0348267 100644
--- a/apk/src/com/android/healthconnect/controller/shared/HealthPermissionReader.kt
+++ b/apk/src/com/android/healthconnect/controller/shared/HealthPermissionReader.kt
@@ -129,19 +129,26 @@
 
     private fun shouldHidePermission(permission: String): Boolean {
         return shouldHideExerciseRoute(permission) ||
-            shouldHideExerciseRouteAll(permission) ||
+            shouldHideReadExerciseRoutes(permission) ||
             shouldHideSessionTypes(permission) ||
-            shouldHideBackgroundReadPermission(permission)
+            shouldHideBackgroundReadPermission(permission) ||
+            shouldHideSkinTemperaturePermissions(permission)
     }
 
     private fun shouldHideExerciseRoute(permission: String): Boolean {
         return permission in exerciseRoutePermissions && !featureUtils.isExerciseRouteEnabled()
     }
 
-    private fun shouldHideExerciseRouteAll(permission: String): Boolean {
-        // TODO(b/300270771): use HealthPermissions.READ_EXERCISE_ROUTES_ALL when the API becomes
+    private fun shouldHideReadExerciseRoutes(permission: String): Boolean {
+        // TODO(b/300270771): use HealthPermissions.READ_EXERCISE_ROUTES when the API becomes
         // unhidden.
-        return permission == "android.permission.health.READ_EXERCISE_ROUTES_ALL"
+        return permission == "android.permission.health.READ_EXERCISE_ROUTES"
+    }
+
+    private fun shouldHideSkinTemperaturePermissions(permission: String): Boolean {
+        // TODO(b/319602927): use skin temperature permissions when the API becomes unhidden.
+        return permission == "android.permission.health.READ_SKIN_TEMPERATURE" ||
+            permission == "android.permission.health.WRITE_SKIN_TEMPERATURE"
     }
 
     private fun shouldHideSessionTypes(permission: String): Boolean {
diff --git a/apk/src/com/android/healthconnect/controller/utils/FeatureUtils.kt b/apk/src/com/android/healthconnect/controller/utils/FeatureUtils.kt
index 9e8f61b..78d509d 100644
--- a/apk/src/com/android/healthconnect/controller/utils/FeatureUtils.kt
+++ b/apk/src/com/android/healthconnect/controller/utils/FeatureUtils.kt
@@ -23,6 +23,8 @@
     fun isNewInformationArchitectureEnabled(): Boolean
 
     fun isBackgroundReadEnabled(): Boolean
+
+    fun isImportExportEnabled(): Boolean
 }
 
 class FeatureUtilsImpl(context: Context) : FeatureUtils, DeviceConfig.OnPropertiesChangedListener {
@@ -38,6 +40,7 @@
             "aggregation_source_controls_enable"
         private const val PROPERTY_NEW_INFORMATION_ARCHITECTURE_ENABLED =
             "new_information_architecture_enable"
+        private const val PROPERTY_IMPORT_EXPORT_ENABLED = "import_export_enable"
     }
 
     private val lock = Any()
@@ -63,10 +66,15 @@
         DeviceConfig.getBoolean(HEALTH_FITNESS_FLAGS_NAMESPACE, PROPERTY_ENTRY_POINTS_ENABLED, true)
 
     private var isNewAppPriorityEnabled = true
+
     private var isNewInformationArchitectureEnabled =
         DeviceConfig.getBoolean(
             HEALTH_FITNESS_FLAGS_NAMESPACE, PROPERTY_NEW_INFORMATION_ARCHITECTURE_ENABLED, false)
 
+    private var isImportExportEnabled =
+        DeviceConfig.getBoolean(
+            HEALTH_FITNESS_FLAGS_NAMESPACE, PROPERTY_IMPORT_EXPORT_ENABLED, false)
+
     override fun isNewAppPriorityEnabled(): Boolean {
         synchronized(lock) {
             return isNewAppPriorityEnabled
@@ -109,16 +117,27 @@
         }
     }
 
+    override fun isImportExportEnabled(): Boolean {
+        synchronized(lock) {
+            return isImportExportEnabled
+        }
+    }
+
     override fun onPropertiesChanged(properties: DeviceConfig.Properties) {
         synchronized(lock) {
             if (!properties.namespace.equals(HEALTH_FITNESS_FLAGS_NAMESPACE)) {
                 return
             }
+
             for (name in properties.keyset) {
                 when (name) {
                     PROPERTY_EXERCISE_ROUTE_ENABLED ->
                         isExerciseRouteEnabled =
                             properties.getBoolean(PROPERTY_EXERCISE_ROUTE_ENABLED, true)
+                    PROPERTY_EXERCISE_ROUTE_READ_ALL_ENABLED -> {
+                        isExerciseRouteReadAllEnabled =
+                            properties.getBoolean(PROPERTY_EXERCISE_ROUTE_READ_ALL_ENABLED, true)
+                    }
                     PROPERTY_SESSIONS_TYPE_ENABLED ->
                         isSessionTypesEnabled =
                             properties.getBoolean(PROPERTY_SESSIONS_TYPE_ENABLED, true)
@@ -130,6 +149,9 @@
                         isNewInformationArchitectureEnabled =
                             properties.getBoolean(
                                 PROPERTY_NEW_INFORMATION_ARCHITECTURE_ENABLED, false)
+                    PROPERTY_IMPORT_EXPORT_ENABLED ->
+                        isImportExportEnabled =
+                            properties.getBoolean(PROPERTY_IMPORT_EXPORT_ENABLED, false)
                 }
             }
         }
diff --git a/apk/tests/Android.bp b/apk/tests/Android.bp
index ba4d2f7..d42a49d 100644
--- a/apk/tests/Android.bp
+++ b/apk/tests/Android.bp
@@ -82,6 +82,7 @@
         "androidx.test.ext.junit",
         "androidx.test.ext.truth",
         "androidx.test.rules",
+        "compatibility-device-util-axt",
         "mockito-kotlin2"
     ],
     resource_dirs: ["main_res"],
diff --git a/apk/tests/TestApp/AndroidManifest.xml b/apk/tests/TestApp/AndroidManifest.xml
index adbd724..ea9cc0d 100644
--- a/apk/tests/TestApp/AndroidManifest.xml
+++ b/apk/tests/TestApp/AndroidManifest.xml
@@ -24,7 +24,7 @@
     <uses-permission android:name="android.permission.health.WRITE_EXERCISE"/>
     <uses-permission android:name="android.permission.health.READ_SLEEP"/>
     <uses-permission android:name="android.permission.health.WRITE_SLEEP"/>
-    <uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTES_ALL"/>
+    <uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTES"/>
     <uses-permission android:name="android.permission.health.WRITE_EXERCISE_ROUTE"/>
     <uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND"/>
     <uses-permission android:name="android.permission.MANAGE_HEALTH_DATA"/>
diff --git a/apk/tests/src/com/android/healthconnect/controller/tests/datasources/DataSourcesFragmentTest.kt b/apk/tests/src/com/android/healthconnect/controller/tests/datasources/DataSourcesFragmentTest.kt
index e1fb751..246cbc4 100644
--- a/apk/tests/src/com/android/healthconnect/controller/tests/datasources/DataSourcesFragmentTest.kt
+++ b/apk/tests/src/com/android/healthconnect/controller/tests/datasources/DataSourcesFragmentTest.kt
@@ -20,11 +20,13 @@
 import androidx.lifecycle.MutableLiveData
 import androidx.test.espresso.Espresso.onIdle
 import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.click
 import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
 import androidx.test.espresso.assertion.ViewAssertions.matches
 import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
 import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
 import androidx.test.espresso.matcher.ViewMatchers.withId
+import androidx.test.espresso.matcher.ViewMatchers.withTagValue
 import androidx.test.espresso.matcher.ViewMatchers.withText
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.healthconnect.controller.R
@@ -62,6 +64,7 @@
 import java.util.Locale
 import java.util.TimeZone
 import org.hamcrest.Matchers.allOf
+import org.hamcrest.Matchers.`is`
 import org.hamcrest.Matchers.not
 import org.junit.After
 import org.junit.Before
@@ -611,4 +614,120 @@
 
         onView(withId(R.id.error_view)).check(matches(isDisplayed()))
     }
+
+    @Test
+    fun triggerEditMode_changesActionItems() {
+        whenever(dataSourcesViewModel.dataSourcesAndAggregationsInfo).then {
+            MutableLiveData(
+                DataSourcesAndAggregationsInfo(
+                    priorityListState =
+                        PriorityListState.WithData(true, listOf(TEST_APP, TEST_APP_2)),
+                    potentialAppSourcesState = PotentialAppSourcesState.WithData(true, listOf()),
+                    aggregationCardsState = AggregationCardsState.WithData(true, listOf())))
+        }
+        whenever(dataSourcesViewModel.getEditedPriorityList()).then { listOf(TEST_APP, TEST_APP_2) }
+        whenever(dataSourcesViewModel.updatedAggregationCardsData).then {
+            MutableLiveData(AggregationCardsState.WithData(true, listOf()))
+        }
+        (appUtils as FakeAppUtils).setDefaultApp(TEST_APP_PACKAGE_NAME)
+        val scenario =
+            launchFragment<DataSourcesFragment>(
+                bundleOf(CATEGORY_KEY to HealthDataCategory.ACTIVITY))
+        onIdle()
+
+        scenario.onActivity { activity ->
+            val fragment = activity.supportFragmentManager.findFragmentByTag("")
+            (fragment as DataSourcesFragment).editPriorityList()
+        }
+
+        onView(withId(R.id.linear_layout_recycle_view))
+            .check(
+                matches(
+                    atPosition(
+                        0,
+                        allOf(
+                            hasDescendant(withText("1")),
+                            hasDescendant(withText(TEST_APP_NAME)),
+                            hasDescendant(withTagValue(`is`("edit_mode")))))))
+
+        onView(withId(R.id.linear_layout_recycle_view))
+            .check(
+                matches(
+                    atPosition(
+                        1,
+                        allOf(
+                            hasDescendant(withText("2")),
+                            hasDescendant(withText(TEST_APP_NAME_2)),
+                            hasDescendant(withTagValue(`is`("edit_mode")))))))
+    }
+
+    @Test
+    fun triggerEditMode_whenChangingCategory_resetsToDrag() {
+        whenever(dataSourcesViewModel.dataSourcesAndAggregationsInfo).then {
+            MutableLiveData(
+                DataSourcesAndAggregationsInfo(
+                    priorityListState =
+                        PriorityListState.WithData(true, listOf(TEST_APP, TEST_APP_2)),
+                    potentialAppSourcesState = PotentialAppSourcesState.WithData(true, listOf()),
+                    aggregationCardsState = AggregationCardsState.WithData(true, listOf())))
+        }
+        whenever(dataSourcesViewModel.getEditedPriorityList()).then { listOf(TEST_APP, TEST_APP_2) }
+        whenever(dataSourcesViewModel.updatedAggregationCardsData).then {
+            MutableLiveData(AggregationCardsState.WithData(true, listOf()))
+        }
+
+        (appUtils as FakeAppUtils).setDefaultApp(TEST_APP_PACKAGE_NAME)
+        val scenario =
+            launchFragment<DataSourcesFragment>(
+                bundleOf(CATEGORY_KEY to HealthDataCategory.ACTIVITY))
+        onIdle()
+
+        scenario.onActivity { activity ->
+            val fragment = activity.supportFragmentManager.findFragmentByTag("")
+            (fragment as DataSourcesFragment).editPriorityList()
+        }
+
+        onView(withId(R.id.linear_layout_recycle_view))
+            .check(
+                matches(
+                    atPosition(
+                        0,
+                        allOf(
+                            hasDescendant(withText("1")),
+                            hasDescendant(withText(TEST_APP_NAME)),
+                            hasDescendant(withTagValue(`is`("edit_mode")))))))
+
+        onView(withId(R.id.linear_layout_recycle_view))
+            .check(
+                matches(
+                    atPosition(
+                        1,
+                        allOf(
+                            hasDescendant(withText("2")),
+                            hasDescendant(withText(TEST_APP_NAME_2)),
+                            hasDescendant(withTagValue(`is`("edit_mode")))))))
+
+        onView(withId(R.id.spinner)).perform(click())
+        onView(withText("Sleep")).perform(click())
+
+        onView(withId(R.id.linear_layout_recycle_view))
+            .check(
+                matches(
+                    atPosition(
+                        0,
+                        allOf(
+                            hasDescendant(withText("1")),
+                            hasDescendant(withText(TEST_APP_NAME)),
+                            hasDescendant(withTagValue(`is`("drag_mode")))))))
+
+        onView(withId(R.id.linear_layout_recycle_view))
+            .check(
+                matches(
+                    atPosition(
+                        1,
+                        allOf(
+                            hasDescendant(withText("2")),
+                            hasDescendant(withText(TEST_APP_NAME_2)),
+                            hasDescendant(withTagValue(`is`("drag_mode")))))))
+    }
 }
diff --git a/apk/tests/src/com/android/healthconnect/controller/tests/route/ExerciseRouteViewModelTest.kt b/apk/tests/src/com/android/healthconnect/controller/tests/route/ExerciseRouteViewModelTest.kt
index ed9481b..8489797 100644
--- a/apk/tests/src/com/android/healthconnect/controller/tests/route/ExerciseRouteViewModelTest.kt
+++ b/apk/tests/src/com/android/healthconnect/controller/tests/route/ExerciseRouteViewModelTest.kt
@@ -24,6 +24,11 @@
 import android.health.connect.datatypes.ExerciseSessionType
 import android.os.OutcomeReceiver
 import androidx.test.platform.app.InstrumentationRegistry
+import com.android.healthconnect.controller.permissions.api.GetGrantedHealthPermissionsUseCase
+import com.android.healthconnect.controller.permissions.api.GetHealthPermissionsFlagsUseCase
+import com.android.healthconnect.controller.permissions.api.GrantHealthPermissionUseCase
+import com.android.healthconnect.controller.permissions.api.HealthPermissionManager
+import com.android.healthconnect.controller.permissions.api.LoadAccessDateUseCase
 import com.android.healthconnect.controller.route.ExerciseRouteViewModel
 import com.android.healthconnect.controller.route.LoadExerciseRouteUseCase
 import com.android.healthconnect.controller.shared.app.AppInfoReader
@@ -36,6 +41,9 @@
 import com.google.common.truth.Truth.assertThat
 import dagger.hilt.android.testing.HiltAndroidRule
 import dagger.hilt.android.testing.HiltAndroidTest
+import java.time.Instant
+import java.util.Locale
+import javax.inject.Inject
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.TestCoroutineDispatcher
@@ -52,9 +60,6 @@
 import org.mockito.Mockito.mock
 import org.mockito.MockitoAnnotations
 import org.mockito.invocation.InvocationOnMock
-import java.time.Instant
-import java.util.Locale
-import javax.inject.Inject
 
 @OptIn(ExperimentalCoroutinesApi::class)
 @HiltAndroidTest
@@ -68,6 +73,7 @@
     @Inject lateinit var appInfoReader: AppInfoReader
 
     var manager: HealthConnectManager = mock(HealthConnectManager::class.java)
+    private val healthPermissionManager = mock(HealthPermissionManager::class.java)
 
     private lateinit var viewModel: ExerciseRouteViewModel
     private lateinit var context: Context
@@ -81,7 +87,13 @@
         Dispatchers.setMain(testDispatcher)
         viewModel =
             ExerciseRouteViewModel(
-                LoadExerciseRouteUseCase(manager, Dispatchers.Main), appInfoReader)
+                context,
+                LoadExerciseRouteUseCase(manager, Dispatchers.Main),
+                GetGrantedHealthPermissionsUseCase(healthPermissionManager),
+                GetHealthPermissionsFlagsUseCase(healthPermissionManager),
+                GrantHealthPermissionUseCase(healthPermissionManager),
+                LoadAccessDateUseCase(healthPermissionManager),
+                appInfoReader)
     }
 
     @After
diff --git a/apk/tests/src/com/android/healthconnect/controller/tests/route/RouteRequestActivityTest.kt b/apk/tests/src/com/android/healthconnect/controller/tests/route/RouteRequestActivityTest.kt
index 6401fbd..04deaaf 100644
--- a/apk/tests/src/com/android/healthconnect/controller/tests/route/RouteRequestActivityTest.kt
+++ b/apk/tests/src/com/android/healthconnect/controller/tests/route/RouteRequestActivityTest.kt
@@ -29,6 +29,7 @@
 import androidx.lifecycle.MutableLiveData
 import androidx.test.core.app.ActivityScenario.launchActivityForResult
 import androidx.test.espresso.Espresso.onView
+import androidx.test.espresso.action.ViewActions.scrollTo
 import androidx.test.espresso.assertion.ViewAssertions.matches
 import androidx.test.espresso.matcher.RootMatchers.isDialog
 import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
@@ -120,6 +121,10 @@
         whenever(migrationViewModel.migrationState).then {
             MutableLiveData(WithData(MigrationState.IDLE))
         }
+
+        whenever(viewModel.isReadRoutesPermissionDeclared(context.packageName)).thenReturn(true)
+        whenever(viewModel.isSessionInaccessible(context.packageName, TEST_SESSION))
+            .thenReturn(false)
     }
 
     @Test
@@ -224,12 +229,11 @@
 
         launchActivityForResult<RouteRequestActivity>(startActivityIntent)
 
-        onView(withText("Don\'t allow")).inRoot(isDialog()).check(matches(isDisplayed()))
-        onView(withText("Allow")).inRoot(isDialog()).check(matches(isDisplayed()))
-        onView(withText("Allow Health Connect to access this exercise route in Health Connect?"))
+        onView(withText("This app will be able to read your past location in the route"))
             .inRoot(isDialog())
             .check(matches(isDisplayed()))
-        onView(withText("This app will be able to read your past location in the route"))
+        onView(withText("Allow this route")).inRoot(isDialog()).check(matches(isDisplayed()))
+        onView(withText("Allow Health Connect to access this exercise route in Health Connect?"))
             .inRoot(isDialog())
             .check(matches(isDisplayed()))
         onView(withText("Session title")).inRoot(isDialog()).check(matches(isDisplayed()))
@@ -237,6 +241,10 @@
             .inRoot(isDialog())
             .check(matches(isDisplayed()))
         onView(withId(R.id.map_view)).inRoot(isDialog()).check(matches(isDisplayed()))
+        onView(withText("Don\'t allow"))
+            .inRoot(isDialog())
+            .perform(scrollTo())
+            .check(matches(isDisplayed()))
     }
 
     @Test
@@ -270,8 +278,7 @@
 
         launchActivityForResult<RouteRequestActivity>(startActivityIntent)
 
-        onView(withText("Don\'t allow")).inRoot(isDialog()).check(matches(isDisplayed()))
-        onView(withText("Allow")).inRoot(isDialog()).check(matches(isDisplayed()))
+        onView(withText("Allow this route")).inRoot(isDialog()).check(matches(isDisplayed()))
         onView(withText("Allow Health Connect to access this exercise route in Health Connect?"))
             .inRoot(isDialog())
             .check(matches(isDisplayed()))
@@ -283,6 +290,10 @@
             .inRoot(isDialog())
             .check(matches(isDisplayed()))
         onView(withId(R.id.map_view)).inRoot(isDialog()).check(matches(isDisplayed()))
+        onView(withText("Don\'t allow"))
+            .inRoot(isDialog())
+            .perform(scrollTo())
+            .check(matches(isDisplayed()))
     }
 
     @Test
diff --git a/apk/tests/src/com/android/healthconnect/controller/tests/shared/HealthPermissionReaderTest.kt b/apk/tests/src/com/android/healthconnect/controller/tests/shared/HealthPermissionReaderTest.kt
index f4b7d25..4926a85 100644
--- a/apk/tests/src/com/android/healthconnect/controller/tests/shared/HealthPermissionReaderTest.kt
+++ b/apk/tests/src/com/android/healthconnect/controller/tests/shared/HealthPermissionReaderTest.kt
@@ -77,7 +77,7 @@
     }
 
     @Test
-    fun getDeclaredPermissions_returnsAllPermissions_exceptReadAllRoutes() = runTest {
+    fun getDeclaredPermissions_returnsAllPermissions_exceptHiddenPermissions() = runTest {
         assertThat(permissionReader.getDeclaredPermissions(TEST_APP_PACKAGE_NAME))
             .containsExactly(
                 HealthPermissions.WRITE_EXERCISE_ROUTE.toHealthPermission(),
diff --git a/apk/tests/src/com/android/healthconnect/controller/tests/utils/LocalDateTimeFormatterTest.kt b/apk/tests/src/com/android/healthconnect/controller/tests/utils/LocalDateTimeFormatterTest.kt
index 47ff0f0..f28af15 100644
--- a/apk/tests/src/com/android/healthconnect/controller/tests/utils/LocalDateTimeFormatterTest.kt
+++ b/apk/tests/src/com/android/healthconnect/controller/tests/utils/LocalDateTimeFormatterTest.kt
@@ -3,6 +3,9 @@
 import android.content.Context
 import android.content.res.Configuration
 import android.os.LocaleList
+import android.provider.Settings.System
+import com.android.compatibility.common.util.UserSettings
+import com.android.compatibility.common.util.UserSettings.Namespace
 import com.android.healthconnect.controller.utils.LocalDateTimeFormatter
 import com.google.common.truth.Truth.assertThat
 import dagger.hilt.android.qualifiers.ApplicationContext
@@ -24,7 +27,9 @@
     @get:Rule val hiltRule = HiltAndroidRule(this)
 
     @Inject @ApplicationContext lateinit var context: Context
+    private lateinit var systemSettings: UserSettings
 
+    private var previousTimeFormat: String? = null
     private var previousDefaultTimeZone: TimeZone? = null
     private var previousLocale: Locale? = null
 
@@ -34,6 +39,13 @@
     fun setup() {
         hiltRule.inject()
 
+        systemSettings = UserSettings(context, Namespace.SYSTEM)
+        previousTimeFormat = systemSettings.get(System.TIME_12_24)
+        if (previousTimeFormat != null) {
+            // Clear setting so locale-defined time format is used.
+            systemSettings.syncSet(System.TIME_12_24, null)
+        }
+
         previousDefaultTimeZone = TimeZone.getDefault()
         previousLocale = Locale.getDefault()
 
@@ -43,6 +55,9 @@
 
     @After
     fun tearDown() {
+        if (previousTimeFormat != null) {
+            systemSettings.syncSet(System.TIME_12_24, previousTimeFormat)
+        }
         TimeZone.setDefault(previousDefaultTimeZone)
         previousLocale?.let { locale -> Locale.setDefault(locale) }
     }
diff --git a/apk/tests/src/com/android/healthconnect/controller/tests/utils/di/FakeFeatureUtils.kt b/apk/tests/src/com/android/healthconnect/controller/tests/utils/di/FakeFeatureUtils.kt
index 46fa9e4..46e26cb 100644
--- a/apk/tests/src/com/android/healthconnect/controller/tests/utils/di/FakeFeatureUtils.kt
+++ b/apk/tests/src/com/android/healthconnect/controller/tests/utils/di/FakeFeatureUtils.kt
@@ -17,6 +17,7 @@
     private var isNewAppPriorityEnabled = false
     private var isNewInformationArchitectureEnabled = false
     private var isBackgroundReadEnabled = false
+    private var isImportExportEnabled = false
 
     fun setIsSessionTypesEnabled(boolean: Boolean) {
         isSessionTypesEnabled = boolean
@@ -46,6 +47,10 @@
         this.isBackgroundReadEnabled = isBackgroundReadEnabled
     }
 
+    fun setIsImportExportEnabled(isImportExportEnabled: Boolean) {
+        this.isImportExportEnabled = isImportExportEnabled
+    }
+
     override fun isNewAppPriorityEnabled(): Boolean {
         return isNewAppPriorityEnabled
     }
@@ -73,6 +78,10 @@
     override fun isBackgroundReadEnabled(): Boolean {
         return isBackgroundReadEnabled
     }
+
+    override fun isImportExportEnabled(): Boolean {
+        return isImportExportEnabled
+    }
 }
 
 @Module
diff --git a/backuprestore/AndroidManifest.xml b/backuprestore/AndroidManifest.xml
index 749d412..ba5f75c 100644
--- a/backuprestore/AndroidManifest.xml
+++ b/backuprestore/AndroidManifest.xml
@@ -21,6 +21,7 @@
         android:killAfterRestore="false"
         android:allowBackup="true"
         android:fullBackupOnly="true"
-        android:backupAgent=".HealthConnectBackupAgent" >
+        android:backupAgent=".HealthConnectBackupAgent"
+        android:restoreAnyVersion="true" >
     </application>
 </manifest>
diff --git a/framework/java/android/health/connect/Constants.java b/framework/java/android/health/connect/Constants.java
index 5282dd5..9b1ac4d 100644
--- a/framework/java/android/health/connect/Constants.java
+++ b/framework/java/android/health/connect/Constants.java
@@ -32,6 +32,7 @@
     public static final long DEFAULT_LONG = -1;
     public static final double DEFAULT_DOUBLE = Double.MIN_VALUE;
     public static final int DEFAULT_PAGE_SIZE = 1000;
+    public static final int MINIMUM_PAGE_SIZE = 1;
     public static final int MAXIMUM_PAGE_SIZE = 5000;
     public static final int MAXIMUM_ALLOWED_CURSOR_COUNT = 100_000;
     public static final int UPSERT = 0;
diff --git a/framework/java/android/health/connect/HealthPermissionCategory.java b/framework/java/android/health/connect/HealthPermissionCategory.java
index f218dc3..8b2efe2 100644
--- a/framework/java/android/health/connect/HealthPermissionCategory.java
+++ b/framework/java/android/health/connect/HealthPermissionCategory.java
@@ -16,6 +16,7 @@
 
 package android.health.connect;
 
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.health.connect.datatypes.ActiveCaloriesBurnedRecord;
@@ -40,13 +41,17 @@
 @SystemApi
 public class HealthPermissionCategory {
     public static final int UNKNOWN = 0;
+
     // ACTIVITY
     /** Permission category for {@link ActiveCaloriesBurnedRecord} */
     public static final int ACTIVE_CALORIES_BURNED = 1;
+
     /** Permission category for {@link DistanceRecord} */
     public static final int DISTANCE = 2;
+
     /** Permission category for {@link ElevationGainedRecord} */
     public static final int ELEVATION_GAINED = 3;
+
     /**
      * Permission category for {@link android.health.connect.datatypes.ExerciseSessionRecord} and
      * {@link android.health.connect.datatypes.ExerciseLap}
@@ -58,71 +63,107 @@
 
     /** Permission category for {@link StepsRecord} */
     public static final int STEPS = 6;
+
     // BODY_MEASUREMENTS
     /** Permission category for {@link BasalMetabolicRateRecord} */
     public static final int BASAL_METABOLIC_RATE = 9;
+
     /** Permission category for {BodyFatRecord} */
     public static final int BODY_FAT = 10;
+
     /** Permission category for {BodyWaterMassRecord} */
     public static final int BODY_WATER_MASS = 11;
 
     /** Permission category for {BoneMassRecord} */
     public static final int BONE_MASS = 12;
+
     /** Permission category for {HeightRecord} */
     public static final int HEIGHT = 13;
+
     /** Permission category for {LeanBodyMassRecord} */
     public static final int LEAN_BODY_MASS = 15;
+
     /** Permission category for {@link PowerRecord} */
     public static final int POWER = 36;
+
     /** Permission category for {@link SpeedRecord} */
     public static final int SPEED = 37;
+
     /** Permission category for {TotalCaloriesBurnedRecord} */
     public static final int TOTAL_CALORIES_BURNED = 35;
+
     /** Permission category for {Vo2MaxRecord} */
     public static final int VO2_MAX = 7;
+
     /** Permission category for {WeightRecord} */
     public static final int WEIGHT = 17;
+
     /** Permission category for {WheelChairPushesRecord} */
     public static final int WHEELCHAIR_PUSHES = 8;
+
     // CYCLE_TRACKING
     /** Permission category for {CervicalMucusRecord} */
     public static final int CERVICAL_MUCUS = 18;
+
     /** Permission category for {IntermenstrualBleedingRecord} */
     public static final int INTERMENSTRUAL_BLEEDING = 38;
+
     /** Permission category for {MenstruationRecord} */
     public static final int MENSTRUATION = 20;
+
     /** Permission category for {OvulationTestRecord} */
     public static final int OVULATION_TEST = 21;
+
     /** Permission category for {SexualActivityRecord} */
     public static final int SEXUAL_ACTIVITY = 22;
+
     // NUTRITION
     /** Permission category for {HydrationRecord} */
     public static final int HYDRATION = 23;
+
     /** Permission category for {NutritionRecord} */
     public static final int NUTRITION = 24;
+
     // SLEEP
     /** Permission category for {BasalBodyTemperatureRecord} */
     public static final int BASAL_BODY_TEMPERATURE = 33;
+
     /** Permission category for {SleepRecord} */
     public static final int SLEEP = 25;
+
     // VITALS
     /** Permission category for {BloodGlucose} */
     public static final int BLOOD_GLUCOSE = 26;
+
     /** Permission category for {BloodPressure} */
     public static final int BLOOD_PRESSURE = 27;
+
     /** Permission category for {BodyTemperature} */
     public static final int BODY_TEMPERATURE = 28;
+
     /** Permission category for {@link HeartRateRecord} */
     public static final int HEART_RATE = 29;
+
     /** Permission category for {HeartRateVariability} */
     public static final int HEART_RATE_VARIABILITY = 30;
+
     /** Permission category for {OxygenSaturation} */
     public static final int OXYGEN_SATURATION = 31;
+
     /** Permission category for {RespiratoryRate} */
     public static final int RESPIRATORY_RATE = 32;
+
     /** Permission category for {RestingHeartRate} */
     public static final int RESTING_HEART_RATE = 34;
 
+    /**
+     * Permission category for {SkinTemperature}
+     *
+     * @hide
+     */
+    @FlaggedApi("com.android.healthconnect.flags.skin_temperature")
+    public static final int SKIN_TEMPERATURE = 39;
+
     private HealthPermissionCategory() {}
 
     /** @hide */
@@ -162,7 +203,8 @@
         HEART_RATE_VARIABILITY,
         OXYGEN_SATURATION,
         RESPIRATORY_RATE,
-        RESTING_HEART_RATE
+        RESTING_HEART_RATE,
+        SKIN_TEMPERATURE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Type {}
diff --git a/framework/java/android/health/connect/HealthPermissions.java b/framework/java/android/health/connect/HealthPermissions.java
index 1b1f42e..dfd2083 100644
--- a/framework/java/android/health/connect/HealthPermissions.java
+++ b/framework/java/android/health/connect/HealthPermissions.java
@@ -45,6 +45,7 @@
 import static android.health.connect.HealthPermissionCategory.RESPIRATORY_RATE;
 import static android.health.connect.HealthPermissionCategory.RESTING_HEART_RATE;
 import static android.health.connect.HealthPermissionCategory.SEXUAL_ACTIVITY;
+import static android.health.connect.HealthPermissionCategory.SKIN_TEMPERATURE;
 import static android.health.connect.HealthPermissionCategory.SLEEP;
 import static android.health.connect.HealthPermissionCategory.SPEED;
 import static android.health.connect.HealthPermissionCategory.STEPS;
@@ -53,6 +54,7 @@
 import static android.health.connect.HealthPermissionCategory.WEIGHT;
 import static android.health.connect.HealthPermissionCategory.WHEELCHAIR_PUSHES;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -183,8 +185,8 @@
      *
      * @hide
      */
-    public static final String READ_EXERCISE_ROUTES_ALL =
-            "android.permission.health.READ_EXERCISE_ROUTES_ALL";
+    public static final String READ_EXERCISE_ROUTES =
+            "android.permission.health.READ_EXERCISE_ROUTES";
 
     /**
      * Allows an application to read the user's floors climbed data.
@@ -421,6 +423,17 @@
             "android.permission.health.READ_RESTING_HEART_RATE";
 
     /**
+     * Allows an application to read the user's skin temperature data.
+     *
+     * <p>Protection level: dangerous.
+     *
+     * @hide
+     */
+    @FlaggedApi("com.android.healthconnect.flags.skin_temperature")
+    public static final String READ_SKIN_TEMPERATURE =
+            "android.permission.health.READ_SKIN_TEMPERATURE";
+
+    /**
      * Allows an application to write the user's calories burned data.
      *
      * <p>Protection level: dangerous.
@@ -694,6 +707,17 @@
     public static final String WRITE_RESTING_HEART_RATE =
             "android.permission.health.WRITE_RESTING_HEART_RATE";
 
+    /**
+     * Allows an application to write the user's skin temperature data.
+     *
+     * <p>Protection level: dangerous.
+     *
+     * @hide
+     */
+    @FlaggedApi("com.android.healthconnect.flags.skin_temperature")
+    public static final String WRITE_SKIN_TEMPERATURE =
+            "android.permission.health.WRITE_SKIN_TEMPERATURE";
+
     private static final Set<String> sWritePermissionsSet =
             new ArraySet<>(
                     Set.of(
@@ -731,7 +755,8 @@
                             WRITE_HEART_RATE_VARIABILITY,
                             WRITE_OXYGEN_SATURATION,
                             WRITE_RESPIRATORY_RATE,
-                            WRITE_RESTING_HEART_RATE));
+                            WRITE_RESTING_HEART_RATE,
+                            WRITE_SKIN_TEMPERATURE));
 
     private static final Map<String, Integer> sWriteHealthPermissionToHealthDataCategoryMap =
             new ArrayMap<>();
@@ -898,6 +923,7 @@
         sHealthCategoryToWritePermissionMap.put(OXYGEN_SATURATION, WRITE_OXYGEN_SATURATION);
         sHealthCategoryToWritePermissionMap.put(RESPIRATORY_RATE, WRITE_RESPIRATORY_RATE);
         sHealthCategoryToWritePermissionMap.put(RESTING_HEART_RATE, WRITE_RESTING_HEART_RATE);
+        sHealthCategoryToWritePermissionMap.put(SKIN_TEMPERATURE, WRITE_SKIN_TEMPERATURE);
 
         // Populate permission category to read permission map
         sHealthCategoryToReadPermissionMap.put(ACTIVE_CALORIES_BURNED, READ_ACTIVE_CALORIES_BURNED);
@@ -936,6 +962,7 @@
         sHealthCategoryToReadPermissionMap.put(OXYGEN_SATURATION, READ_OXYGEN_SATURATION);
         sHealthCategoryToReadPermissionMap.put(RESPIRATORY_RATE, READ_RESPIRATORY_RATE);
         sHealthCategoryToReadPermissionMap.put(RESTING_HEART_RATE, READ_RESTING_HEART_RATE);
+        sHealthCategoryToReadPermissionMap.put(SKIN_TEMPERATURE, READ_SKIN_TEMPERATURE);
     }
 
     private static synchronized void populateWriteHealthPermissionToHealthDataCategoryMap() {
@@ -999,6 +1026,8 @@
         sWriteHealthPermissionToHealthDataCategoryMap.put(
                 WRITE_BASAL_BODY_TEMPERATURE, HealthDataCategory.VITALS);
         sWriteHealthPermissionToHealthDataCategoryMap.put(
+                WRITE_SKIN_TEMPERATURE, HealthDataCategory.VITALS);
+        sWriteHealthPermissionToHealthDataCategoryMap.put(
                 WRITE_BLOOD_GLUCOSE, HealthDataCategory.VITALS);
         sWriteHealthPermissionToHealthDataCategoryMap.put(
                 WRITE_BLOOD_PRESSURE, HealthDataCategory.VITALS);
diff --git a/framework/java/android/health/connect/HealthServicesInitializer.java b/framework/java/android/health/connect/HealthServicesInitializer.java
index ba2a372..6525825 100644
--- a/framework/java/android/health/connect/HealthServicesInitializer.java
+++ b/framework/java/android/health/connect/HealthServicesInitializer.java
@@ -19,6 +19,7 @@
 import android.annotation.SystemApi;
 import android.app.SystemServiceRegistry;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.health.connect.aidl.IHealthConnectService;
 
 /**
@@ -42,9 +43,20 @@
                 Context.HEALTHCONNECT_SERVICE,
                 HealthConnectManager.class,
                 (context, serviceBinder) -> {
+                    if (!isHardwareSupported(context)) {
+                        return null;
+                    }
                     IHealthConnectService service =
                             IHealthConnectService.Stub.asInterface(serviceBinder);
                     return new HealthConnectManager(context, service);
                 });
     }
+
+    private static boolean isHardwareSupported(Context context) {
+        PackageManager pm = context.getPackageManager();
+        return (!pm.hasSystemFeature(PackageManager.FEATURE_EMBEDDED)
+                && !pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+                && !pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+                && !pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
+    }
 }
diff --git a/framework/java/android/health/connect/ReadRecordsRequestUsingFilters.java b/framework/java/android/health/connect/ReadRecordsRequestUsingFilters.java
index 0fa107a..b4669e0 100644
--- a/framework/java/android/health/connect/ReadRecordsRequestUsingFilters.java
+++ b/framework/java/android/health/connect/ReadRecordsRequestUsingFilters.java
@@ -19,6 +19,7 @@
 import static android.health.connect.Constants.DEFAULT_LONG;
 import static android.health.connect.Constants.DEFAULT_PAGE_SIZE;
 import static android.health.connect.Constants.MAXIMUM_PAGE_SIZE;
+import static android.health.connect.Constants.MINIMUM_PAGE_SIZE;
 
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -163,9 +164,11 @@
          */
         @NonNull
         public Builder<T> setPageSize(@IntRange(from = 1, to = 5000) int pageSize) {
-            if (pageSize > MAXIMUM_PAGE_SIZE) {
+            if (pageSize < MINIMUM_PAGE_SIZE || pageSize > MAXIMUM_PAGE_SIZE) {
                 throw new IllegalArgumentException(
-                        "Maximum allowed pageSize is "
+                        "Valid pageSize range is "
+                                + MINIMUM_PAGE_SIZE
+                                + " - "
                                 + MAXIMUM_PAGE_SIZE
                                 + ", requested "
                                 + pageSize);
diff --git a/framework/java/android/health/connect/datatypes/BodyTemperatureRecord.java b/framework/java/android/health/connect/datatypes/BodyTemperatureRecord.java
index 648aa8c..664ffb3 100644
--- a/framework/java/android/health/connect/datatypes/BodyTemperatureRecord.java
+++ b/framework/java/android/health/connect/datatypes/BodyTemperatureRecord.java
@@ -29,7 +29,7 @@
 
 /**
  * Captures the body temperature of a user. Each record represents a single instantaneous body
- * temperature measuremen
+ * temperature measurement.
  */
 @Identifier(recordIdentifier = RecordTypeIdentifier.RECORD_TYPE_BODY_TEMPERATURE)
 public final class BodyTemperatureRecord extends InstantRecord {
diff --git a/service/java/com/android/server/healthconnect/HealthConnectDeviceConfigManager.java b/service/java/com/android/server/healthconnect/HealthConnectDeviceConfigManager.java
index 8e7c734..b3a3c13 100644
--- a/service/java/com/android/server/healthconnect/HealthConnectDeviceConfigManager.java
+++ b/service/java/com/android/server/healthconnect/HealthConnectDeviceConfigManager.java
@@ -44,6 +44,8 @@
 public class HealthConnectDeviceConfigManager implements DeviceConfig.OnPropertiesChangedListener {
     private static Set<String> sFlagsToTrack = new ArraySet<>();
     private static final String EXERCISE_ROUTE_FEATURE_FLAG = "exercise_routes_enable";
+    private static final String EXERCISE_ROUTES_READ_ALL_FEATURE_FLAG =
+            "exercise_routes_read_all_enable";
     public static final String ENABLE_RATE_LIMITER_FLAG = "enable_rate_limiter";
     private static final String MAX_READ_REQUESTS_PER_24H_FOREGROUND_FLAG =
             "max_read_requests_per_24h_foreground";
@@ -124,6 +126,7 @@
 
     private static final boolean SESSION_DATATYPE_DEFAULT_FLAG_VALUE = true;
     private static final boolean EXERCISE_ROUTE_DEFAULT_FLAG_VALUE = true;
+    private static final boolean EXERCISE_ROUTES_READ_ALL_DEFAULT_FLAG_VALUE = true;
     public static final boolean ENABLE_RATE_LIMITER_DEFAULT_FLAG_VALUE = true;
     public static final int QUOTA_BUCKET_READS_PER_15M_FOREGROUND_DEFAULT_FLAG_VALUE = 2000;
     public static final int QUOTA_BUCKET_READS_PER_24H_FOREGROUND_DEFAULT_FLAG_VALUE = 16000;
@@ -186,6 +189,13 @@
                     EXERCISE_ROUTE_DEFAULT_FLAG_VALUE);
 
     @GuardedBy("mLock")
+    private boolean mExerciseRoutesReadAllEnabled =
+            DeviceConfig.getBoolean(
+                    HEALTH_FITNESS_NAMESPACE,
+                    EXERCISE_ROUTES_READ_ALL_FEATURE_FLAG,
+                    EXERCISE_ROUTES_READ_ALL_DEFAULT_FLAG_VALUE);
+
+    @GuardedBy("mLock")
     private boolean mSessionDatatypeEnabled =
             DeviceConfig.getBoolean(
                     HEALTH_FITNESS_NAMESPACE,
@@ -308,6 +318,7 @@
     /** Adds flags that need to be updated if their values are changed on the server. */
     private static void addFlagsToTrack() {
         sFlagsToTrack.add(EXERCISE_ROUTE_FEATURE_FLAG);
+        sFlagsToTrack.add(EXERCISE_ROUTES_READ_ALL_FEATURE_FLAG);
         sFlagsToTrack.add(SESSION_DATATYPE_FEATURE_FLAG);
         sFlagsToTrack.add(ENABLE_RATE_LIMITER_FLAG);
         sFlagsToTrack.add(COUNT_MIGRATION_STATE_IN_PROGRESS_FLAG);
@@ -336,6 +347,16 @@
         }
     }
 
+    /** Returns true if READ_EXERCISE_ROUTES permission is effective. */
+    public boolean isExerciseRoutesReadAllFeatureEnabled() {
+        mLock.readLock().lock();
+        try {
+            return mExerciseRoutesReadAllEnabled;
+        } finally {
+            mLock.readLock().unlock();
+        }
+    }
+
     @GuardedBy("mLock")
     private boolean mRateLimiterEnabled =
             DeviceConfig.getBoolean(
@@ -610,6 +631,12 @@
                                         EXERCISE_ROUTE_FEATURE_FLAG,
                                         EXERCISE_ROUTE_DEFAULT_FLAG_VALUE);
                         break;
+                    case EXERCISE_ROUTES_READ_ALL_FEATURE_FLAG:
+                        mExerciseRoutesReadAllEnabled =
+                                properties.getBoolean(
+                                        EXERCISE_ROUTES_READ_ALL_FEATURE_FLAG,
+                                        EXERCISE_ROUTES_READ_ALL_DEFAULT_FLAG_VALUE);
+                        break;
                     case SESSION_DATATYPE_FEATURE_FLAG:
                         mSessionDatatypeEnabled =
                                 properties.getBoolean(
diff --git a/service/java/com/android/server/healthconnect/HealthConnectServiceImpl.java b/service/java/com/android/server/healthconnect/HealthConnectServiceImpl.java
index 003b810..70eb882 100644
--- a/service/java/com/android/server/healthconnect/HealthConnectServiceImpl.java
+++ b/service/java/com/android/server/healthconnect/HealthConnectServiceImpl.java
@@ -607,10 +607,9 @@
 
                         boolean enforceSelfRead = false;
 
-                        if (!holdsDataManagementPermission) {
-                            final boolean isInForeground =
-                                    mAppOpsManagerLocal.isUidInForeground(uid);
+                        final boolean isInForeground = mAppOpsManagerLocal.isUidInForeground(uid);
 
+                        if (!holdsDataManagementPermission) {
                             logger.setCallerForegroundState(isInForeground);
 
                             tryAcquireApiCallQuota(
@@ -651,12 +650,9 @@
                                                 + enforceSelfRead);
                             }
                         }
-                        final Map<String, Boolean> extraReadPermsToGrantState =
-                                Collections.unmodifiableMap(
-                                        mDataPermissionEnforcer
-                                                .collectExtraReadPermissionToStateMapping(
-                                                        Set.of(request.getRecordType()),
-                                                        attributionSource));
+                        final Set<String> grantedExtraReadPermissions =
+                                mDataPermissionEnforcer.collectGrantedExtraReadPermissions(
+                                        Set.of(request.getRecordType()), attributionSource);
 
                         Trace.traceBegin(TRACE_TAG_READ, TAG_READ);
                         try {
@@ -683,7 +679,8 @@
                                             request,
                                             startDateAccessEpochMilli,
                                             enforceSelfRead,
-                                            extraReadPermsToGrantState);
+                                            grantedExtraReadPermissions,
+                                            isInForeground);
                             // throw an exception if read requested is not for a single record type
                             // i.e. size of read table request is not equal to 1.
                             if (readTransactionRequest.getReadRequests().size() != 1) {
@@ -1030,8 +1027,8 @@
                                 ChangeLogsHelper.getRecordTypeToInsertedUuids(
                                         changeLogsResponse.getChangeLogsMap());
 
-                        Map<String, Boolean> extraReadPermsToGrantState =
-                                mDataPermissionEnforcer.collectExtraReadPermissionToStateMapping(
+                        Set<String> grantedExtraReadPermissions =
+                                mDataPermissionEnforcer.collectGrantedExtraReadPermissions(
                                         recordTypeToInsertedUuids.keySet(), attributionSource);
 
                         List<RecordInternal<?>> recordInternals =
@@ -1040,7 +1037,8 @@
                                                 callerPackageName,
                                                 recordTypeToInsertedUuids,
                                                 startDateAccessEpochMilli,
-                                                extraReadPermsToGrantState));
+                                                grantedExtraReadPermissions,
+                                                isInForeground));
 
                         List<DeletedLog> deletedLogs =
                                 ChangeLogsHelper.getDeletedLogs(
diff --git a/service/java/com/android/server/healthconnect/backuprestore/BackupRestore.java b/service/java/com/android/server/healthconnect/backuprestore/BackupRestore.java
index 352a95e..d586f02 100644
--- a/service/java/com/android/server/healthconnect/backuprestore/BackupRestore.java
+++ b/service/java/com/android/server/healthconnect/backuprestore/BackupRestore.java
@@ -152,7 +152,13 @@
     @VisibleForTesting
     static final long DATA_MERGING_TIMEOUT_INTERVAL_MILLIS = 5 * DateUtils.DAY_IN_MILLIS;
 
-    private static final long DATA_MERGING_RETRY_DELAY_MILLIS = 12 * DateUtils.HOUR_IN_MILLIS;
+    @VisibleForTesting
+    static final long DATA_MERGING_RETRY_DELAY_MILLIS = 12 * DateUtils.HOUR_IN_MILLIS;
+
+    // Used in #setOverrideDeadline to set a minimum window of 24 hours. See b/311402873,
+    // b/319721118
+    @VisibleForTesting
+    static final long MINIMUM_LATENCY_WINDOW_MILLIS = 24 * DateUtils.HOUR_IN_MILLIS;
 
     @VisibleForTesting static final String DATA_DOWNLOAD_TIMEOUT_KEY = "data_download_timeout_key";
 
@@ -719,8 +725,8 @@
 
         // We might be here because the device rebooted or the user switched. If a timer was already
         // going on then we want to continue that timer.
-        long timeout =
-                getRemainingTimeout(
+        long timeoutMillis =
+                getRemainingTimeoutMillis(
                         DATA_DOWNLOAD_TIMEOUT_KEY,
                         DATA_DOWNLOAD_TIMEOUT_CANCELLED_KEY,
                         DATA_DOWNLOAD_TIMEOUT_INTERVAL_MILLIS);
@@ -734,9 +740,11 @@
                                 BackupRestoreJobService.BACKUP_RESTORE_JOB_ID + userId,
                                 new ComponentName(mContext, BackupRestoreJobService.class))
                         .setExtras(extras)
-                        .setMinimumLatency(timeout)
-                        .setOverrideDeadline(timeout << 1);
-        Slog.i(TAG, "Scheduling download state timeout job with period: " + timeout);
+                        .setMinimumLatency(timeoutMillis)
+                        .setOverrideDeadline(timeoutMillis + MINIMUM_LATENCY_WINDOW_MILLIS);
+        Slog.i(
+                TAG,
+                "Scheduling download state timeout job with period: " + timeoutMillis + " millis");
         BackupRestoreJobService.schedule(mContext, jobInfoBuilder.build(), this);
 
         // Set the start time
@@ -776,8 +784,8 @@
 
         // We might be here because the device rebooted or the user switched. If a timer was already
         // going on then we want to continue that timer.
-        long timeout =
-                getRemainingTimeout(
+        long timeoutMillis =
+                getRemainingTimeoutMillis(
                         DATA_STAGING_TIMEOUT_KEY,
                         DATA_STAGING_TIMEOUT_CANCELLED_KEY,
                         DATA_STAGING_TIMEOUT_INTERVAL_MILLIS);
@@ -791,9 +799,9 @@
                                 BackupRestoreJobService.BACKUP_RESTORE_JOB_ID + userId,
                                 new ComponentName(mContext, BackupRestoreJobService.class))
                         .setExtras(extras)
-                        .setMinimumLatency(timeout)
-                        .setOverrideDeadline(timeout << 1);
-        Slog.i(TAG, "Scheduling staging timeout job with period: " + timeout);
+                        .setMinimumLatency(timeoutMillis)
+                        .setOverrideDeadline(timeoutMillis + MINIMUM_LATENCY_WINDOW_MILLIS);
+        Slog.i(TAG, "Scheduling staging timeout job with period: " + timeoutMillis + " millis");
         BackupRestoreJobService.schedule(mContext, jobInfoBuilder.build(), this);
 
         // Set the start time
@@ -832,8 +840,8 @@
 
         // We might be here because the device rebooted or the user switched. If a timer was already
         // going on then we want to continue that timer.
-        long timeout =
-                getRemainingTimeout(
+        long timeoutMillis =
+                getRemainingTimeoutMillis(
                         DATA_MERGING_TIMEOUT_KEY,
                         DATA_MERGING_TIMEOUT_CANCELLED_KEY,
                         DATA_MERGING_TIMEOUT_INTERVAL_MILLIS);
@@ -847,9 +855,9 @@
                                 BackupRestoreJobService.BACKUP_RESTORE_JOB_ID + userId,
                                 new ComponentName(mContext, BackupRestoreJobService.class))
                         .setExtras(extras)
-                        .setMinimumLatency(timeout)
-                        .setOverrideDeadline(timeout << 1);
-        Slog.i(TAG, "Scheduling merging timeout job with period: " + timeout);
+                        .setMinimumLatency(timeoutMillis)
+                        .setOverrideDeadline(timeoutMillis + MINIMUM_LATENCY_WINDOW_MILLIS);
+        Slog.i(TAG, "Scheduling merging timeout job with period: " + timeoutMillis + " millis");
         BackupRestoreJobService.schedule(mContext, jobInfoBuilder.build(), this);
 
         // Set the start time
@@ -891,8 +899,8 @@
 
         // We might be here because the device rebooted or the user switched. If a timer was already
         // going on then we want to continue that timer.
-        long timeout =
-                getRemainingTimeout(
+        long timeoutMillis =
+                getRemainingTimeoutMillis(
                         DATA_MERGING_RETRY_KEY,
                         DATA_MERGING_RETRY_CANCELLED_KEY,
                         DATA_MERGING_RETRY_DELAY_MILLIS);
@@ -901,9 +909,9 @@
                                 BackupRestoreJobService.BACKUP_RESTORE_JOB_ID + userId,
                                 new ComponentName(mContext, BackupRestoreJobService.class))
                         .setExtras(extras)
-                        .setMinimumLatency(timeout)
-                        .setOverrideDeadline(timeout << 1);
-        Slog.i(TAG, "Scheduling retry merging job with period: " + timeout);
+                        .setMinimumLatency(timeoutMillis)
+                        .setOverrideDeadline(timeoutMillis + MINIMUM_LATENCY_WINDOW_MILLIS);
+        Slog.i(TAG, "Scheduling retry merging job with period: " + timeoutMillis + " millis");
         BackupRestoreJobService.schedule(mContext, jobInfoBuilder.build(), this);
 
         // Set the start time
@@ -941,7 +949,7 @@
         });
     }
 
-    private long getRemainingTimeout(
+    private long getRemainingTimeoutMillis(
             String startTimeKey, String cancelledTimeKey, long stdTimeout) {
         String startTimeStr = PreferenceHelper.getInstance().getPreference(startTimeKey);
         if (startTimeStr == null || startTimeStr.trim().isEmpty()) {
@@ -1078,11 +1086,8 @@
                         .setPageToken(requestToken.encode())
                         .build();
 
-        Map<String, Boolean> extraReadPermsMapping = new ArrayMap<>();
-        List<String> extraReadPerms = recordHelper.getExtraReadPermissions();
-        for (var extraReadPerm : extraReadPerms) {
-            extraReadPermsMapping.put(extraReadPerm, true);
-        }
+        Set<String> grantedExtraReadPermissions =
+                Set.copyOf(recordHelper.getExtraReadPermissions());
 
         // Working with startDateAccess of -1 as we don't want to have time based filtering in the
         // query.
@@ -1091,9 +1096,12 @@
                 new ReadTransactionRequest(
                         null,
                         readRecordsRequest.toReadRecordsRequestParcel(),
-                        DEFAULT_LONG /* startDateAccessMillis */,
-                        false,
-                        extraReadPermsMapping);
+                        // Avoid time based filtering.
+                        /* startDateAccessMillis= */ DEFAULT_LONG,
+                        /* enforceSelfRead= */ false,
+                        grantedExtraReadPermissions,
+                        // Make sure foreground only types get included in the response.
+                        /* isInForeground= */ true);
 
         List<RecordInternal<?>> recordInternalList;
         PageTokenWrapper token;
diff --git a/service/java/com/android/server/healthconnect/permission/DataPermissionEnforcer.java b/service/java/com/android/server/healthconnect/permission/DataPermissionEnforcer.java
index 62146e9..8f32b5c 100644
--- a/service/java/com/android/server/healthconnect/permission/DataPermissionEnforcer.java
+++ b/service/java/com/android/server/healthconnect/permission/DataPermissionEnforcer.java
@@ -19,7 +19,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.health.connect.HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND;
 
-import static java.util.stream.Collectors.toMap;
+import static java.util.stream.Collectors.toSet;
 
 import android.annotation.NonNull;
 import android.content.AttributionSource;
@@ -40,7 +40,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.Function;
 
 /**
  * Helper class to force caller of data apis to hold api required permissions.
@@ -189,20 +188,19 @@
     }
 
     /**
-     * Collects extra read permissions to its grant state. Used to not expose extra data if caller
-     * doesn't have corresponding permission.
+     * Returns granted extra read permissions.
+     *
+     * <p>Used to not expose extra data if caller doesn't have corresponding permission.
      */
-    public Map<String, Boolean> collectExtraReadPermissionToStateMapping(
+    public Set<String> collectGrantedExtraReadPermissions(
             Set<Integer> recordTypeIds, AttributionSource attributionSource) {
         RecordHelperProvider recordHelperProvider = RecordHelperProvider.getInstance();
         return recordTypeIds.stream()
                 .map(recordHelperProvider::getRecordHelper)
                 .flatMap(recordHelper -> recordHelper.getExtraReadPermissions().stream())
                 .distinct()
-                .collect(
-                        toMap(
-                                Function.identity(),
-                                permission -> isPermissionGranted(permission, attributionSource)));
+                .filter(permission -> isPermissionGranted(permission, attributionSource))
+                .collect(toSet());
     }
 
     public Map<String, Boolean> collectExtraWritePermissionStateMapping(
diff --git a/service/java/com/android/server/healthconnect/storage/datatypehelpers/ExerciseSessionRecordHelper.java b/service/java/com/android/server/healthconnect/storage/datatypehelpers/ExerciseSessionRecordHelper.java
index c76625d..2fa6921 100644
--- a/service/java/com/android/server/healthconnect/storage/datatypehelpers/ExerciseSessionRecordHelper.java
+++ b/service/java/com/android/server/healthconnect/storage/datatypehelpers/ExerciseSessionRecordHelper.java
@@ -19,6 +19,7 @@
 import static android.health.connect.Constants.DEFAULT_LONG;
 import static android.health.connect.HealthConnectException.ERROR_UNSUPPORTED_OPERATION;
 import static android.health.connect.HealthPermissions.READ_EXERCISE_ROUTE;
+import static android.health.connect.HealthPermissions.READ_EXERCISE_ROUTES;
 import static android.health.connect.HealthPermissions.WRITE_EXERCISE_ROUTE;
 import static android.health.connect.datatypes.AggregationType.AggregationTypeIdentifier.EXERCISE_SESSION_DURATION_TOTAL;
 
@@ -71,6 +72,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.UUID;
 
 /**
@@ -249,9 +251,12 @@
     List<ReadTableRequest> getExtraDataReadRequests(
             ReadRecordsRequestParcel request,
             String packageName,
-            long startDateAccess,
-            Map<String, Boolean> extraPermsState) {
-        int routeAccessType = getExerciseRouteReadAccessType(packageName, extraPermsState);
+            long startDateAccessMillis,
+            Set<String> grantedExtraReadPermissions,
+            boolean isInForeground) {
+        int routeAccessType =
+                getExerciseRouteReadAccessType(
+                        packageName, grantedExtraReadPermissions, isInForeground);
 
         if (routeAccessType == ROUTE_READ_ACCESS_TYPE_NONE) {
             return Collections.emptyList();
@@ -260,7 +265,8 @@
         boolean enforceSelfRead = routeAccessType == ROUTE_READ_ACCESS_TYPE_OWN;
 
         WhereClauses sessionsWithAccessibleRouteClause =
-                getReadTableWhereClause(request, packageName, enforceSelfRead, startDateAccess);
+                getReadTableWhereClause(
+                        request, packageName, enforceSelfRead, startDateAccessMillis);
         return List.of(getRouteReadRequest(sessionsWithAccessibleRouteClause));
     }
 
@@ -302,7 +308,7 @@
     /** Returns permissions required to read extra record data. */
     @Override
     public List<String> getExtraReadPermissions() {
-        return Collections.singletonList(READ_EXERCISE_ROUTE);
+        return List.of(READ_EXERCISE_ROUTE, READ_EXERCISE_ROUTES);
     }
 
     public List<String> getExtraWritePermissions() {
@@ -317,8 +323,11 @@
             String packageName,
             List<UUID> uuids,
             long startDateAccess,
-            Map<String, Boolean> extraPermsState) {
-        int routeAccessType = getExerciseRouteReadAccessType(packageName, extraPermsState);
+            Set<String> grantedExtraReadPermissions,
+            boolean isInForeground) {
+        int routeAccessType =
+                getExerciseRouteReadAccessType(
+                        packageName, grantedExtraReadPermissions, isInForeground);
 
         if (routeAccessType == ROUTE_READ_ACCESS_TYPE_NONE) {
             return Collections.emptyList();
@@ -364,6 +373,12 @@
                         .isExerciseRouteFeatureEnabled();
     }
 
+    private boolean isReadExerciseRouteAllFeatureEnabled() {
+        return isExerciseRouteFeatureEnabled()
+                && HealthConnectDeviceConfigManager.getInitialisedInstance()
+                        .isExerciseRoutesReadAllFeatureEnabled();
+    }
+
     @Override
     public void logUpsertMetrics(
             @NonNull List<RecordInternal<?>> recordInternals, @NonNull String packageName) {
@@ -420,17 +435,31 @@
         return routeReadRequest;
     }
 
+    // TODO(b/319821477): disallow reading own routes without any granted ER permission.
     private int getExerciseRouteReadAccessType(
-            String packageName, Map<String, Boolean> extraPermsState) {
+            String packageName, Set<String> grantedExtraReadPermissions, boolean isInForeground) {
         if (!isExerciseRouteFeatureEnabled()) {
             return ROUTE_READ_ACCESS_TYPE_NONE;
         }
 
-        if (extraPermsState.getOrDefault(READ_EXERCISE_ROUTE, false)) {
+        boolean isController = grantedExtraReadPermissions.contains(READ_EXERCISE_ROUTE);
+
+        if (isController) {
+            // HC UI Controller has access to all routes.
             return ROUTE_READ_ACCESS_TYPE_ALL;
         }
 
         long appId = AppInfoHelper.getInstance().getAppInfoId(packageName);
-        return appId == DEFAULT_LONG ? ROUTE_READ_ACCESS_TYPE_NONE : ROUTE_READ_ACCESS_TYPE_OWN;
+
+        if (appId == DEFAULT_LONG) {
+            return ROUTE_READ_ACCESS_TYPE_NONE;
+        }
+
+        boolean canReadAllRoutes =
+                isInForeground
+                        && isReadExerciseRouteAllFeatureEnabled()
+                        && grantedExtraReadPermissions.contains(READ_EXERCISE_ROUTES);
+
+        return canReadAllRoutes ? ROUTE_READ_ACCESS_TYPE_ALL : ROUTE_READ_ACCESS_TYPE_OWN;
     }
 }
diff --git a/service/java/com/android/server/healthconnect/storage/datatypehelpers/RecordHelper.java b/service/java/com/android/server/healthconnect/storage/datatypehelpers/RecordHelper.java
index 13be24f..eaad64b 100644
--- a/service/java/com/android/server/healthconnect/storage/datatypehelpers/RecordHelper.java
+++ b/service/java/com/android/server/healthconnect/storage/datatypehelpers/RecordHelper.java
@@ -76,6 +76,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 import java.util.UUID;
 
 /**
@@ -334,19 +335,27 @@
             ReadRecordsRequestParcel request,
             String callingPackageName,
             boolean enforceSelfRead,
-            long startDateAccess,
-            Map<String, Boolean> extraPermsState) {
+            long startDateAccessMillis,
+            Set<String> grantedExtraReadPermissions,
+            boolean isInForeground) {
         return new ReadTableRequest(getMainTableName())
                 .setJoinClause(getJoinForReadRequest())
                 .setWhereClause(
                         getReadTableWhereClause(
-                                request, callingPackageName, enforceSelfRead, startDateAccess))
+                                request,
+                                callingPackageName,
+                                enforceSelfRead,
+                                startDateAccessMillis))
                 .setOrderBy(getOrderByClause(request))
                 .setLimit(getLimitSize(request))
                 .setRecordHelper(this)
                 .setExtraReadRequests(
                         getExtraDataReadRequests(
-                                request, callingPackageName, startDateAccess, extraPermsState));
+                                request,
+                                callingPackageName,
+                                startDateAccessMillis,
+                                grantedExtraReadPermissions,
+                                isInForeground));
     }
 
     /**
@@ -372,11 +381,12 @@
     }
 
     /** Returns ReadTableRequest for {@code uuids} */
-    public ReadTableRequest getReadTableRequest(
+    public final ReadTableRequest getReadTableRequest(
             String packageName,
             List<UUID> uuids,
             long startDateAccess,
-            Map<String, Boolean> extraPermsState) {
+            Set<String> grantedExtraReadPermissions,
+            boolean isInForeground) {
         return new ReadTableRequest(getMainTableName())
                 .setJoinClause(getJoinForReadRequest())
                 .setWhereClause(
@@ -388,7 +398,11 @@
                 .setRecordHelper(this)
                 .setExtraReadRequests(
                         getExtraDataReadRequests(
-                                packageName, uuids, startDateAccess, extraPermsState));
+                                packageName,
+                                uuids,
+                                startDateAccess,
+                                grantedExtraReadPermissions,
+                                isInForeground));
     }
 
     /**
@@ -399,19 +413,21 @@
             ReadRecordsRequestParcel request,
             String packageName,
             long startDateAccess,
-            Map<String, Boolean> extraPermsState) {
+            Set<String> grantedExtraReadPermissions,
+            boolean isInForeground) {
         return Collections.emptyList();
     }
 
     /**
-     * Returns list if ReadSingleTableRequest for {@code uuids} to populate extra data. Called in
+     * Returns a list of ReadSingleTableRequest for {@code uuids} to populate extra data. Called in
      * change logs read requests.
      */
     List<ReadTableRequest> getExtraDataReadRequests(
             String packageName,
             List<UUID> uuids,
             long startDateAccess,
-            Map<String, Boolean> extraPermsState) {
+            Set<String> grantedExtraReadPermissions,
+            boolean isInForeground) {
         return Collections.emptyList();
     }
 
@@ -698,7 +714,6 @@
             long startDateAccessMillis) {
         AppInfoHelper appInfoHelper = AppInfoHelper.getInstance();
         long callingAppInfoId = appInfoHelper.getAppInfoId(callingPackageName);
-
         RecordIdFiltersParcel recordIdFiltersParcel = request.getRecordIdFiltersParcel();
         if (recordIdFiltersParcel == null) {
             List<Long> appInfoIds =
diff --git a/service/java/com/android/server/healthconnect/storage/request/ReadTransactionRequest.java b/service/java/com/android/server/healthconnect/storage/request/ReadTransactionRequest.java
index a928e15..1937f44 100644
--- a/service/java/com/android/server/healthconnect/storage/request/ReadTransactionRequest.java
+++ b/service/java/com/android/server/healthconnect/storage/request/ReadTransactionRequest.java
@@ -31,6 +31,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.Set;
 import java.util.UUID;
 
 /**
@@ -54,7 +55,8 @@
             ReadRecordsRequestParcel request,
             long startDateAccessMillis,
             boolean enforceSelfRead,
-            Map<String, Boolean> extraPermsState) {
+            Set<String> grantedExtraReadPermissions,
+            boolean isInForeground) {
         RecordHelper<?> recordHelper =
                 RecordHelperProvider.getInstance().getRecordHelper(request.getRecordType());
         mReadTableRequests =
@@ -64,7 +66,8 @@
                                 callingPackageName,
                                 enforceSelfRead,
                                 startDateAccessMillis,
-                                extraPermsState));
+                                grantedExtraReadPermissions,
+                                isInForeground));
         if (request.getRecordIdFiltersParcel() == null) {
             mPageToken = PageTokenWrapper.from(request.getPageToken(), request.isAscending());
             mPageSize = request.getPageSize();
@@ -77,8 +80,9 @@
     public ReadTransactionRequest(
             String packageName,
             Map<Integer, List<UUID>> recordTypeToUuids,
-            long startDateAccess,
-            Map<String, Boolean> extraPermsState) {
+            long startDateAccessMillis,
+            Set<String> grantedExtraReadPermissions,
+            boolean isInForeground) {
         mReadTableRequests = new ArrayList<>();
         recordTypeToUuids.forEach(
                 (recordType, uuids) ->
@@ -88,8 +92,9 @@
                                         .getReadTableRequest(
                                                 packageName,
                                                 uuids,
-                                                startDateAccess,
-                                                extraPermsState)));
+                                                startDateAccessMillis,
+                                                grantedExtraReadPermissions,
+                                                isInForeground)));
         mPageSize = DEFAULT_INT;
         mPageToken = null;
     }
diff --git a/testapps/toolbox/AndroidManifest.xml b/testapps/toolbox/AndroidManifest.xml
index f9c1c06..1c8a6ee 100644
--- a/testapps/toolbox/AndroidManifest.xml
+++ b/testapps/toolbox/AndroidManifest.xml
@@ -31,7 +31,7 @@
   <uses-permission android:name="android.permission.health.READ_DISTANCE" />
   <uses-permission android:name="android.permission.health.READ_ELEVATION_GAINED" />
   <uses-permission android:name="android.permission.health.READ_EXERCISE" />
-  <uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTES_ALL" />
+  <uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTES" />
   <uses-permission android:name="android.permission.health.READ_FLOORS_CLIMBED" />
   <uses-permission android:name="android.permission.health.READ_HEART_RATE" />
   <uses-permission android:name="android.permission.health.READ_HEART_RATE_VARIABILITY" />
diff --git a/testapps/toolbox/src/com/android/healthconnect/testapps/toolbox/Constants.kt b/testapps/toolbox/src/com/android/healthconnect/testapps/toolbox/Constants.kt
index 9cc6f93..5d7f573 100644
--- a/testapps/toolbox/src/com/android/healthconnect/testapps/toolbox/Constants.kt
+++ b/testapps/toolbox/src/com/android/healthconnect/testapps/toolbox/Constants.kt
@@ -82,7 +82,7 @@
             "android.permission.health.READ_DISTANCE",
             "android.permission.health.READ_ELEVATION_GAINED",
             "android.permission.health.READ_EXERCISE",
-            "android.permission.health.READ_EXERCISE_ROUTES_ALL",
+            "android.permission.health.READ_EXERCISE_ROUTES",
             "android.permission.health.READ_FLOORS_CLIMBED",
             "android.permission.health.READ_HEART_RATE",
             "android.permission.health.READ_HEART_RATE_VARIABILITY",
diff --git a/tests/cts/Android.bp b/tests/cts/Android.bp
index 712094e..60e8eb7 100644
--- a/tests/cts/Android.bp
+++ b/tests/cts/Android.bp
@@ -30,6 +30,11 @@
         ":healthfitness-cts-testapp-srcs",
         ":healthfitness-permissions-testapp-srcs",
         "src/android/healthconnect/cts/*.java",
+        "src/android/healthconnect/cts/aggregation/*.java",
+        "src/android/healthconnect/cts/changelogs/*.java",
+        "src/android/healthconnect/cts/datatypes/**/*.java",
+        "src/android/healthconnect/cts/migration/*.java",
+        "src/android/healthconnect/cts/readdata/*.java",
     ],
     // Tag this module as a cts test artifact
     test_suites: [
@@ -116,7 +121,7 @@
         "compatibility-device-util-axt",
         "ctstestrunner-axt",
         "cts-wm-util",
-	"modules-utils-build",
+        "modules-utils-build",
         "testng",
         "cts-healthconnect-utils",
     ],
@@ -166,7 +171,7 @@
             ":HealthFitnessCtsTestApp",
             ":HealthFitnessCtsTestApp2",
             ":CtsHealthConnectTestAppAWithNormalReadWritePermission",
-            ":CtsHealthConnectTestAppBWithNormalReadWritePermission"
+            ":CtsHealthConnectTestAppBWithNormalReadWritePermission",
         ],
 }
 
diff --git a/tests/cts/AndroidManifestUI.xml b/tests/cts/AndroidManifestUI.xml
index 44eb971..50a2a29 100644
--- a/tests/cts/AndroidManifestUI.xml
+++ b/tests/cts/AndroidManifestUI.xml
@@ -21,6 +21,7 @@
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner"/>
+        <activity android:name="android.healthconnect.cts.utils.ProxyActivity"/>
     </application>
 
     <!-- To get visibility of the app with health permissions definitions,
@@ -84,6 +85,7 @@
     <uses-permission android:name="android.permission.health.WRITE_DISTANCE"/>
     <uses-permission android:name="android.permission.health.WRITE_ELEVATION_GAINED"/>
     <uses-permission android:name="android.permission.health.WRITE_EXERCISE"/>
+    <uses-permission android:name="android.permission.health.WRITE_EXERCISE_ROUTE"/>
     <uses-permission android:name="android.permission.health.WRITE_FLOORS_CLIMBED"/>
     <uses-permission android:name="android.permission.health.WRITE_HEART_RATE"/>
     <uses-permission android:name="android.permission.health.WRITE_HEART_RATE_VARIABILITY"/>
diff --git a/tests/cts/hostsidetests/healthconnect/HealthConnectTestHelper/CtsHealthConnectTestAppAWithNormalReadWritePermission.xml b/tests/cts/hostsidetests/healthconnect/HealthConnectTestHelper/CtsHealthConnectTestAppAWithNormalReadWritePermission.xml
index d63e110..8ba9256 100644
--- a/tests/cts/hostsidetests/healthconnect/HealthConnectTestHelper/CtsHealthConnectTestAppAWithNormalReadWritePermission.xml
+++ b/tests/cts/hostsidetests/healthconnect/HealthConnectTestHelper/CtsHealthConnectTestAppAWithNormalReadWritePermission.xml
@@ -68,6 +68,7 @@
     <uses-permission android:name="android.permission.health.READ_WHEELCHAIR_PUSHES"/>
     <uses-permission android:name="android.permission.health.READ_DISTANCE"/>
     <uses-permission android:name="android.permission.health.READ_EXERCISE"/>
+    <uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTES"/>
     <uses-permission android:name="android.permission.health.READ_VO2_MAX"/>
     <uses-permission android:name="android.permission.health.READ_POWER"/>
     <uses-permission android:name="android.permission.health.READ_SPEED"/>
@@ -107,6 +108,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.healthconnect.cts.utils.ProxyActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.healthconnect.cts.ACTION_START_ACTIVITY_FOR_RESULT"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+
         <receiver android:name="android.healthconnect.cts.testhelper.TestAppReceiver"
             android:exported="true"/>
     </application>
diff --git a/tests/cts/hostsidetests/healthconnect/HealthConnectTestHelper/src/android/healthconnect/cts/testhelper/TestAppHelper.java b/tests/cts/hostsidetests/healthconnect/HealthConnectTestHelper/src/android/healthconnect/cts/testhelper/TestAppHelper.java
index a57d9e6..fc5a03a 100644
--- a/tests/cts/hostsidetests/healthconnect/HealthConnectTestHelper/src/android/healthconnect/cts/testhelper/TestAppHelper.java
+++ b/tests/cts/hostsidetests/healthconnect/HealthConnectTestHelper/src/android/healthconnect/cts/testhelper/TestAppHelper.java
@@ -16,643 +16,109 @@
 
 package android.healthconnect.cts.testhelper;
 
-import static android.healthconnect.cts.lib.MultiAppTestUtils.APP_PKG_NAME_USED_IN_DATA_ORIGIN;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.CHANGE_LOGS_RESPONSE;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.CHANGE_LOG_TOKEN;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.CLIENT_ID;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.DATA_ORIGIN_FILTER_PACKAGE_NAMES;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.DELETE_RECORDS_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.END_TIME;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.EXERCISE_SESSION;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.GET_CHANGE_LOG_TOKEN_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.INSERT_RECORD_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.INTENT_EXCEPTION;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.PAUSE_END;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.PAUSE_START;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.QUERY_TYPE;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.READ_CHANGE_LOGS_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.READ_RECORDS_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.READ_RECORDS_SIZE;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.READ_RECORD_CLASS_NAME;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.READ_USING_DATA_ORIGIN_FILTERS;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.RECORD_IDS;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.RECORD_TYPE;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.START_TIME;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.STEPS_COUNT;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.STEPS_RECORD;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.SUCCESS;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.UPDATE_EXERCISE_ROUTE;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.UPDATE_RECORDS_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.UPSERT_EXERCISE_ROUTE;
-import static android.healthconnect.cts.utils.TestUtils.buildExerciseSession;
-import static android.healthconnect.cts.utils.TestUtils.buildStepsRecord;
-import static android.healthconnect.cts.utils.TestUtils.getChangeLogs;
-import static android.healthconnect.cts.utils.TestUtils.getExerciseSessionRecord;
-import static android.healthconnect.cts.utils.TestUtils.getTestRecords;
-import static android.healthconnect.cts.utils.TestUtils.insertRecords;
-import static android.healthconnect.cts.utils.TestUtils.insertRecordsAndGetIds;
-import static android.healthconnect.cts.utils.TestUtils.readRecords;
-import static android.healthconnect.cts.utils.TestUtils.updateRecords;
-import static android.healthconnect.cts.utils.TestUtils.verifyDeleteRecords;
+import static android.healthconnect.cts.lib.BundleHelper.DELETE_RECORDS_QUERY;
+import static android.healthconnect.cts.lib.BundleHelper.GET_CHANGE_LOG_TOKEN_QUERY;
+import static android.healthconnect.cts.lib.BundleHelper.INSERT_RECORDS_QUERY;
+import static android.healthconnect.cts.lib.BundleHelper.INTENT_EXCEPTION;
+import static android.healthconnect.cts.lib.BundleHelper.QUERY_TYPE;
+import static android.healthconnect.cts.lib.BundleHelper.READ_CHANGE_LOGS_QUERY;
+import static android.healthconnect.cts.lib.BundleHelper.READ_RECORDS_QUERY;
+import static android.healthconnect.cts.lib.BundleHelper.READ_RECORDS_USING_IDS_QUERY;
+import static android.healthconnect.cts.lib.BundleHelper.UPDATE_RECORDS_QUERY;
 
 import android.content.Context;
 import android.content.Intent;
 import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.ReadRecordsRequestUsingIds;
 import android.health.connect.RecordIdFilter;
 import android.health.connect.changelog.ChangeLogTokenRequest;
 import android.health.connect.changelog.ChangeLogTokenResponse;
 import android.health.connect.changelog.ChangeLogsRequest;
 import android.health.connect.changelog.ChangeLogsResponse;
-import android.health.connect.datatypes.DataOrigin;
-import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
-import android.health.connect.datatypes.StepsRecord;
+import android.healthconnect.cts.lib.BundleHelper;
 import android.healthconnect.cts.utils.TestUtils;
 import android.os.Bundle;
 
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 final class TestAppHelper {
 
     static Intent handleRequest(Context context, Bundle bundle) {
         String queryType = bundle.getString(QUERY_TYPE);
-        Intent returnIntent;
+        Intent response = new Intent(queryType);
         try {
-            switch (queryType) {
-                case INSERT_RECORD_QUERY:
-                    if (bundle.containsKey(APP_PKG_NAME_USED_IN_DATA_ORIGIN)) {
-                        returnIntent =
-                                insertRecordsWithDifferentPkgName(
-                                        queryType,
-                                        bundle.getString(APP_PKG_NAME_USED_IN_DATA_ORIGIN),
-                                        context);
-                        break;
-                    }
-                    if (bundle.containsKey(CLIENT_ID)) {
-                        returnIntent =
-                                insertRecordsWithGivenClientId(
-                                        queryType, bundle.getDouble(CLIENT_ID), context);
-                        break;
-                    }
-                    if (bundle.containsKey(RECORD_TYPE)) {
-                        if (bundle.getString(RECORD_TYPE).equals(STEPS_RECORD)) {
-                            returnIntent =
-                                    insertStepsRecord(
-                                            queryType,
-                                            bundle.getString(START_TIME),
-                                            bundle.getString(END_TIME),
-                                            bundle.getInt(STEPS_COUNT),
-                                            context);
-                            break;
-                        } else if (bundle.getString(RECORD_TYPE).equals(EXERCISE_SESSION)) {
-                            returnIntent =
-                                    insertExerciseSession(
-                                            queryType,
-                                            bundle.getString(START_TIME),
-                                            bundle.getString(END_TIME),
-                                            bundle.getString(PAUSE_START),
-                                            bundle.getString(PAUSE_END),
-                                            context);
-                            break;
-                        }
-                    }
-                    returnIntent = insertRecord(queryType, context);
-                    break;
-                case DELETE_RECORDS_QUERY:
-                    returnIntent =
-                            deleteRecords(
-                                    queryType,
-                                    (List<TestUtils.RecordTypeAndRecordIds>)
-                                            bundle.getSerializable(RECORD_IDS),
-                                    context);
-                    break;
-                case UPDATE_EXERCISE_ROUTE:
-                    returnIntent = updateRoute(queryType, context);
-                    break;
-                case UPSERT_EXERCISE_ROUTE:
-                    returnIntent = upsertRoute(queryType, context);
-                    break;
-                case UPDATE_RECORDS_QUERY:
-                    returnIntent =
-                            updateRecords(
-                                    queryType,
-                                    (List<TestUtils.RecordTypeAndRecordIds>)
-                                            bundle.getSerializable(RECORD_IDS),
-                                    context);
-                    break;
-                case READ_RECORDS_QUERY:
-                    if (bundle.containsKey(READ_USING_DATA_ORIGIN_FILTERS)) {
-                        List<String> dataOriginPackageNames =
-                                bundle.containsKey(DATA_ORIGIN_FILTER_PACKAGE_NAMES)
-                                        ?
-                                        // if a set of data origin filters is specified, use that
-                                        bundle.getStringArrayList(DATA_ORIGIN_FILTER_PACKAGE_NAMES)
-                                        :
-                                        // otherwise default to this app's package name
-                                        List.of(context.getPackageName());
-                        returnIntent =
-                                readRecordsUsingDataOriginFilters(
-                                        queryType,
-                                        bundle.getStringArrayList(READ_RECORD_CLASS_NAME),
-                                        dataOriginPackageNames,
-                                        context);
-                        break;
-                    }
-                    returnIntent =
-                            readRecords(
-                                    queryType,
-                                    bundle.getStringArrayList(READ_RECORD_CLASS_NAME),
-                                    context);
-                    break;
-                case READ_CHANGE_LOGS_QUERY:
-                    returnIntent =
-                            readChangeLogsUsingDataOriginFilters(
-                                    queryType, bundle.getString(CHANGE_LOG_TOKEN), context);
-                    break;
-                case GET_CHANGE_LOG_TOKEN_QUERY:
-                    if (bundle.containsKey(READ_RECORD_CLASS_NAME)) {
-                        returnIntent =
-                                getChangeLogToken(
-                                        queryType,
-                                        bundle.getString(APP_PKG_NAME_USED_IN_DATA_ORIGIN),
-                                        bundle.getStringArrayList(READ_RECORD_CLASS_NAME),
-                                        context);
-                        break;
-                    }
-                    returnIntent =
-                            getChangeLogToken(
-                                    queryType,
-                                    bundle.getString(APP_PKG_NAME_USED_IN_DATA_ORIGIN),
-                                    context);
-                    break;
-                default:
-                    throw new IllegalStateException(
-                            "Unknown query received from launcher app: " + queryType);
-            }
+            Bundle responseBundle = handleRequestUnchecked(context, bundle, queryType);
+            response.putExtras(responseBundle);
         } catch (Exception e) {
-            returnIntent = new Intent(queryType);
-            returnIntent.putExtra(INTENT_EXCEPTION, e);
+            response.putExtra(INTENT_EXCEPTION, e);
         }
-
-        return returnIntent;
+        return response;
     }
 
-    /**
-     * Method to get test records, insert them, and put the list of recordId and recordClass in the
-     * intent
-     *
-     * @param queryType - specifies the action, here it should be INSERT_RECORDS_QUERY
-     * @param context - application context
-     * @return Intent to send back to the main app which is running the tests
-     */
-    private static Intent insertRecord(String queryType, Context context) {
-        List<Record> records = getTestRecords(context.getPackageName());
-        final Intent intent = new Intent(queryType);
-        try {
-            List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                    insertRecordsAndGetIds(records, context);
-            intent.putExtra(RECORD_IDS, (Serializable) listOfRecordIdsAndClass);
-            intent.putExtra(SUCCESS, true);
-        } catch (Exception e) {
-            intent.putExtra(SUCCESS, false);
-            intent.putExtra(INTENT_EXCEPTION, e);
-        }
-
-        return intent;
-    }
-
-    /**
-     * Method to delete the records and put the Exception in the intent if deleting records throws
-     * an exception
-     *
-     * @param queryType - specifies the action, here it should be DELETE_RECORDS_QUERY
-     * @param listOfRecordIdsAndClassName - list of recordId and recordClass of records to be
-     *     deleted
-     * @param context - application context
-     * @return Intent to send back to the main app which is running the tests
-     * @throws ClassNotFoundException if a record category class is not found for any class name
-     *     present in the list @listOfRecordIdsAndClassName
-     */
-    private static Intent deleteRecords(
-            String queryType,
-            List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClassName,
-            Context context)
-            throws ClassNotFoundException {
-        final Intent intent = new Intent(queryType);
-
-        List<RecordIdFilter> recordIdFilters = new ArrayList<>();
-        for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds :
-                listOfRecordIdsAndClassName) {
-            for (String recordId : recordTypeAndRecordIds.getRecordIds()) {
-                recordIdFilters.add(
-                        RecordIdFilter.fromId(
-                                (Class<? extends Record>)
-                                        Class.forName(recordTypeAndRecordIds.getRecordType()),
-                                recordId));
-            }
-        }
-        try {
-            verifyDeleteRecords(recordIdFilters, context);
-            intent.putExtra(SUCCESS, true);
-        } catch (Exception e) {
-            intent.putExtra(INTENT_EXCEPTION, e);
-        }
-        return intent;
-    }
-
-    /**
-     * Method to update the records and put the exception in the intent if updating the records
-     * throws an exception
-     *
-     * @param queryType - specifies the action, here it should be UPDATE_RECORDS_QUERY
-     * @param listOfRecordIdsAndClassName - list of recordId and recordClass of records to be
-     *     updated
-     * @param context - application context
-     * @return Intent to send back to the main app which is running the tests
-     */
-    private static Intent updateRecords(
-            String queryType,
-            List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClassName,
-            Context context) {
-        final Intent intent = new Intent(queryType);
-
-        try {
-            for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds :
-                    listOfRecordIdsAndClassName) {
-                List<? extends Record> recordsToBeUpdated =
-                        TestUtils.readRecords(
-                                new ReadRecordsRequestUsingFilters.Builder<>(
-                                                (Class<? extends Record>)
-                                                        Class.forName(
-                                                                recordTypeAndRecordIds
-                                                                        .getRecordType()))
-                                        .build(),
-                                context);
-                TestUtils.updateRecords((List<Record>) recordsToBeUpdated, context);
-            }
-            intent.putExtra(SUCCESS, true);
-        } catch (Exception e) {
-            intent.putExtra(INTENT_EXCEPTION, e);
-            intent.putExtra(SUCCESS, false);
-        }
-
-        return intent;
-    }
-
-    /**
-     * Method to update the session record to the session without route and put the exception in the
-     * intent if updating the record throws an exception
-     *
-     * @param queryType - specifies the action, here it should be UPDATE_RECORDS_QUERY
-     * @param context - application context
-     * @return Intent to send back to the main app which is running the tests
-     */
-    private static Intent updateRoute(String queryType, Context context) {
-        final Intent intent = new Intent(queryType);
-        try {
-            ExerciseSessionRecord existingSession =
-                    TestUtils.readRecords(
-                                    new ReadRecordsRequestUsingFilters.Builder<>(
-                                                    ExerciseSessionRecord.class)
-                                            .build(),
-                                    context)
-                            .get(0);
-            TestUtils.updateRecords(
-                    List.of(
-                            getExerciseSessionRecord(
-                                    context.getPackageName(),
-                                    Double.parseDouble(
-                                            existingSession.getMetadata().getClientRecordId()),
-                                    false)),
-                    context);
-            intent.putExtra(SUCCESS, true);
-        } catch (Exception e) {
-            intent.putExtra(INTENT_EXCEPTION, e);
-            intent.putExtra(SUCCESS, false);
-        }
-
-        return intent;
-    }
-
-    /**
-     * Method to upsert the session record to the session without route and put the exception in the
-     * intent if updating the record throws an exception
-     *
-     * @param queryType - specifies the action, here it should be UPDATE_RECORDS_QUERY
-     * @param context - application context
-     * @return Intent to send back to the main app which is running the tests
-     */
-    private static Intent upsertRoute(String queryType, Context context) {
-        final Intent intent = new Intent(queryType);
-        try {
-            ExerciseSessionRecord existingSession =
-                    TestUtils.readRecords(
-                                    new ReadRecordsRequestUsingFilters.Builder<>(
-                                                    ExerciseSessionRecord.class)
-                                            .build(),
-                                    context)
-                            .get(0);
-            insertRecords(
-                    List.of(
-                            getExerciseSessionRecord(
-                                    context.getPackageName(),
-                                    Double.parseDouble(
-                                            existingSession.getMetadata().getClientRecordId()),
-                                    false)),
-                    context);
-            intent.putExtra(SUCCESS, true);
-        } catch (Exception e) {
-            intent.putExtra(INTENT_EXCEPTION, e);
-            intent.putExtra(SUCCESS, false);
-        }
-
-        return intent;
-    }
-
-    /**
-     * Method to insert records with different package name in dataOrigin of the record and add the
-     * details in the intent
-     *
-     * @param queryType - specifies the action, here it should be INSERT_RECORDS_QUERY
-     * @param pkgNameUsedInDataOrigin - package name to be added in the dataOrigin of the records
-     * @param context - application context
-     * @return Intent to send back to the main app which is running the tests
-     * @throws InterruptedException
-     */
-    private static Intent insertRecordsWithDifferentPkgName(
-            String queryType, String pkgNameUsedInDataOrigin, Context context)
-            throws InterruptedException {
-        final Intent intent = new Intent(queryType);
-
-        List<Record> recordsToBeInserted = getTestRecords(pkgNameUsedInDataOrigin);
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                insertRecordsAndGetIds(recordsToBeInserted, context);
-
-        intent.putExtra(RECORD_IDS, (Serializable) listOfRecordIdsAndClass);
-        return intent;
-    }
-
-    /**
-     * Method to read records and put the number of records read in the intent or put the exception
-     * in the intent in case reading records throws exception
-     *
-     * @param queryType - specifies the action, here it should be READ_RECORDS_QUERY
-     * @param recordClassesToRead - List of Record Class names for the records to be read
-     * @param context - application context
-     * @return Intent to send back to the main app which is running the tests
-     */
-    private static Intent readRecords(
-            String queryType, ArrayList<String> recordClassesToRead, Context context) {
-        final Intent intent = new Intent(queryType);
-        int recordsSize = 0;
-        try {
-            for (String recordClass : recordClassesToRead) {
-                List<? extends Record> recordsRead =
-                        TestUtils.readRecords(
-                                new ReadRecordsRequestUsingFilters.Builder<>(
-                                                (Class<? extends Record>)
-                                                        Class.forName(recordClass))
-                                        .build(),
-                                context);
-
-                recordsSize += recordsRead.size();
-            }
-            intent.putExtra(SUCCESS, true);
-        } catch (Exception e) {
-            intent.putExtra(INTENT_EXCEPTION, e);
-            intent.putExtra(SUCCESS, false);
-        }
-
-        intent.putExtra(READ_RECORDS_SIZE, recordsSize);
-
-        return intent;
-    }
-
-    /**
-     * Method to insert records with given clientId in their dataOrigin and put SUCCESS as true if
-     * insertion is successfule or SUCCESS as false if insertion throws an exception
-     *
-     * @param queryType - specifies the action, here it should be INSERT_RECORDS_QUERY
-     * @param clientId - clientId to be specified in the dataOrigin of the records to be inserted
-     * @param context - application context
-     * @return Intent to send back to the main app which is running the tests
-     */
-    private static Intent insertRecordsWithGivenClientId(
-            String queryType, double clientId, Context context) {
-        final Intent intent = new Intent(queryType);
-
-        List<Record> records = getTestRecords(context.getPackageName(), clientId);
-
-        try {
-            insertRecords(records, context);
-            intent.putExtra(SUCCESS, true);
-        } catch (Exception e) {
-            intent.putExtra(SUCCESS, false);
-        }
-
-        return intent;
-    }
-
-    /**
-     * Method to read records using data origin filters and add number of records read to the intent
-     *
-     * @param queryType - specifies the action, here it should be READ_RECORDS_QUERY
-     * @param recordClassesToRead - List of Record Class names for the records to be read
-     * @param context - application context
-     * @return Intent to send back to the main app which is running the tests
-     */
-    private static Intent readRecordsUsingDataOriginFilters(
-            String queryType,
-            ArrayList<String> recordClassesToRead,
-            List<String> dataOriginPackageNames,
-            Context context) {
-        final Intent intent = new Intent(queryType);
-
-        int recordsSize = 0;
-        try {
-            for (String recordClass : recordClassesToRead) {
-                ReadRecordsRequestUsingFilters.Builder requestBuilder =
-                        new ReadRecordsRequestUsingFilters.Builder<>(
-                                (Class<? extends Record>) Class.forName(recordClass));
-                dataOriginPackageNames.forEach(
-                        packageName ->
-                                requestBuilder.addDataOrigins(
-                                        new DataOrigin.Builder()
-                                                .setPackageName(packageName)
-                                                .build()));
-                List<? extends Record> recordsRead =
-                        TestUtils.readRecords(requestBuilder.build(), context);
-                recordsSize += recordsRead.size();
-            }
-        } catch (Exception e) {
-            intent.putExtra(READ_RECORDS_SIZE, 0);
-            intent.putExtra(INTENT_EXCEPTION, e);
-        }
-
-        intent.putExtra(READ_RECORDS_SIZE, recordsSize);
-
-        return intent;
-    }
-
-    /**
-     * Method to read changeLogs using dataOriginFilters and add the changeLogToken
-     *
-     * @param queryType - specifies the action, here it should be
-     *     READ_CHANGE_LOGS_USING_DATA_ORIGIN_FILTERS_QUERY
-     * @param context - application context
-     * @param changeLogToken - Token corresponding to which changeLogs have to be read
-     * @return Intent to send back to the main app which is running the tests
-     */
-    private static Intent readChangeLogsUsingDataOriginFilters(
-            String queryType, String changeLogToken, Context context) {
-        final Intent intent = new Intent(queryType);
-
-        ChangeLogsRequest changeLogsRequest = new ChangeLogsRequest.Builder(changeLogToken).build();
-
-        try {
-            ChangeLogsResponse response = getChangeLogs(changeLogsRequest, context);
-            intent.putExtra(CHANGE_LOGS_RESPONSE, response);
-        } catch (Exception e) {
-            intent.putExtra(INTENT_EXCEPTION, e);
-        }
-
-        return intent;
-    }
-
-    /**
-     * Method to get changeLogToken for an app
-     *
-     * @param queryType - specifies the action, here it should be GET_CHANGE_LOG_TOKEN_QUERY
-     * @param pkgName - pkgName of the app whose changeLogs we have to read using the returned token
-     * @param context - application context
-     * @return - Intent to send back to the main app which is running the tests
-     */
-    private static Intent getChangeLogToken(String queryType, String pkgName, Context context)
+    private static Bundle handleRequestUnchecked(Context context, Bundle bundle, String queryType)
             throws Exception {
-        final Intent intent = new Intent(queryType);
-
-        ChangeLogTokenResponse tokenResponse =
-                TestUtils.getChangeLogToken(
-                        new ChangeLogTokenRequest.Builder()
-                                .addDataOriginFilter(
-                                        new DataOrigin.Builder().setPackageName(pkgName).build())
-                                .build(),
-                        context);
-
-        intent.putExtra(CHANGE_LOG_TOKEN, tokenResponse.getToken());
-        return intent;
+        return switch (queryType) {
+            case INSERT_RECORDS_QUERY -> handleInsertRecords(context, bundle);
+            case DELETE_RECORDS_QUERY -> handleDeleteRecords(context, bundle);
+            case UPDATE_RECORDS_QUERY -> handleUpdateRecords(context, bundle);
+            case READ_RECORDS_QUERY -> handleReadRecords(context, bundle);
+            case READ_RECORDS_USING_IDS_QUERY -> handleReadRecordsUsingIds(context, bundle);
+            case READ_CHANGE_LOGS_QUERY -> handleGetChangeLogs(context, bundle);
+            case GET_CHANGE_LOG_TOKEN_QUERY -> handleGetChangeLogToken(context, bundle);
+            default -> throw new IllegalStateException(
+                    "Unknown query received from launcher app: " + queryType);
+        };
     }
 
-    /**
-     * Method to get changeLogToken for an app
-     *
-     * @param queryType - specifies the action, here it should be GET_CHANGE_LOG_TOKEN_QUERY
-     * @param pkgName - pkgName of the app whose changeLogs we have to read using the returned token
-     * @param recordClassesToRead - Record Classes whose changeLogs to be read using the returned
-     *     token
-     * @param context - application context
-     * @return - Intent to send back to the main app which is running the tests
-     */
-    private static Intent getChangeLogToken(
-            String queryType,
-            String pkgName,
-            ArrayList<String> recordClassesToRead,
-            Context context)
+    private static Bundle handleInsertRecords(Context context, Bundle bundle) throws Exception {
+        List<? extends Record> records = BundleHelper.toInsertRecordsRequest(bundle);
+        List<Record> insertedRecords = TestUtils.insertRecords(records, context);
+        List<String> response =
+                insertedRecords.stream().map(Record::getMetadata).map(Metadata::getId).toList();
+        return BundleHelper.fromInsertRecordsResponse(response);
+    }
+
+    private static Bundle handleReadRecords(Context context, Bundle bundle) throws Exception {
+        ReadRecordsRequestUsingFilters<? extends Record> request =
+                BundleHelper.toReadRecordsRequestUsingFilters(bundle);
+        List<? extends Record> records = TestUtils.readRecords(request, context);
+        return BundleHelper.fromReadRecordsResponse(records);
+    }
+
+    private static Bundle handleReadRecordsUsingIds(Context context, Bundle bundle)
             throws Exception {
-        final Intent intent = new Intent(queryType);
-
-        ChangeLogTokenRequest.Builder changeLogTokenRequestBuilder =
-                new ChangeLogTokenRequest.Builder()
-                        .addDataOriginFilter(
-                                new DataOrigin.Builder().setPackageName(pkgName).build());
-        for (String recordClass : recordClassesToRead) {
-            changeLogTokenRequestBuilder.addRecordType(
-                    (Class<? extends Record>) Class.forName(recordClass));
-        }
-        ChangeLogTokenResponse tokenResponse =
-                TestUtils.getChangeLogToken(changeLogTokenRequestBuilder.build(), context);
-
-        intent.putExtra(CHANGE_LOG_TOKEN, tokenResponse.getToken());
-        return intent;
+        ReadRecordsRequestUsingIds<? extends Record> request =
+                BundleHelper.toReadRecordsRequestUsingIds(bundle);
+        List<? extends Record> records = TestUtils.readRecords(request, context);
+        return BundleHelper.fromReadRecordsResponse(records);
     }
 
-    /**
-     * Method to build steps record and insert them
-     *
-     * @param queryType - specifies the action, here it should be INSERT_RECORDS_QUERY
-     * @param startTime - start time for the steps record to build
-     * @param endTime - end time for the steps record to build
-     * @param stepsCount - number of steps to be added in the steps record
-     * @param context - application context
-     * @return Intent to send back to the main app which is running the tests
-     */
-    private static Intent insertStepsRecord(
-            String queryType, String startTime, String endTime, int stepsCount, Context context) {
-        final Intent intent = new Intent(queryType);
-        try {
-            List<Record> recordToInsert =
-                    Arrays.asList(
-                            buildStepsRecord(
-                                    startTime, endTime, stepsCount, context.getPackageName()));
-            List<Record> insertedRecords = insertRecords(recordToInsert, context);
-            List<TestUtils.RecordTypeAndRecordIds> recordTypeAndRecordIdsList =
-                    new ArrayList<TestUtils.RecordTypeAndRecordIds>();
-            recordTypeAndRecordIdsList.add(
-                    new TestUtils.RecordTypeAndRecordIds(
-                            StepsRecord.class.getName(),
-                            List.of(insertedRecords.get(0).getMetadata().getId())));
-            intent.putExtra(SUCCESS, true);
-            intent.putExtra(RECORD_IDS, (Serializable) recordTypeAndRecordIdsList);
-        } catch (Exception e) {
-            intent.putExtra(SUCCESS, false);
-        }
-        return intent;
+    private static Bundle handleDeleteRecords(Context context, Bundle bundle) throws Exception {
+        List<RecordIdFilter> recordIdFilters = BundleHelper.toDeleteRecordsByIdsRequest(bundle);
+
+        TestUtils.verifyDeleteRecords(recordIdFilters, context);
+
+        return new Bundle();
     }
 
-    /**
-     * Method to build Exercise Session records and insert them
-     *
-     * @param queryType - specifies the action, here it should be INSERT_RECORDS_QUERY
-     * @param sessionStartTime - start time of the exercise session to build
-     * @param sessionEndTime - end time of the exercise session t build
-     * @param pauseStart - start time of the pause segment in the exercise session
-     * @param pauseEnd - end time of the pause segment in the exercise session
-     * @param context - application context
-     * @return Intent to send back to the main app which is running the tests
-     */
-    private static Intent insertExerciseSession(
-            String queryType,
-            String sessionStartTime,
-            String sessionEndTime,
-            String pauseStart,
-            String pauseEnd,
-            Context context) {
-        final Intent intent = new Intent(queryType);
-        try {
-            List<Record> recordToInsert;
-            if (pauseStart == null) {
-                recordToInsert =
-                        Arrays.asList(
-                                buildExerciseSession(sessionStartTime, sessionEndTime, context));
-            } else {
-                recordToInsert =
-                        Arrays.asList(
-                                buildExerciseSession(
-                                        sessionStartTime,
-                                        sessionEndTime,
-                                        pauseStart,
-                                        pauseEnd,
-                                        context));
-            }
-            insertRecords(recordToInsert, context);
-            intent.putExtra(SUCCESS, true);
-        } catch (Exception e) {
-            intent.putExtra(SUCCESS, false);
-        }
-        return intent;
+    private static Bundle handleUpdateRecords(Context context, Bundle bundle) throws Exception {
+        List<? extends Record> records = BundleHelper.toUpdateRecordsRequest(bundle);
+        TestUtils.updateRecords(records, context);
+        return new Bundle();
+    }
+
+    private static Bundle handleGetChangeLogToken(Context context, Bundle bundle) throws Exception {
+        ChangeLogTokenRequest request = BundleHelper.toChangeLogTokenRequest(bundle);
+        ChangeLogTokenResponse response = TestUtils.getChangeLogToken(request, context);
+        return BundleHelper.fromChangeLogTokenResponse(response.getToken());
+    }
+
+    private static Bundle handleGetChangeLogs(Context context, Bundle bundle) throws Exception {
+        ChangeLogsRequest request = BundleHelper.toChangeLogsRequest(bundle);
+        ChangeLogsResponse response = TestUtils.getChangeLogs(request, context);
+        return BundleHelper.fromChangeLogsResponse(response);
     }
 
     private TestAppHelper() {}
diff --git a/tests/cts/hostsidetests/healthconnect/device/src/android/healthconnect/cts/device/ExerciseRouteAccessTest.java b/tests/cts/hostsidetests/healthconnect/device/src/android/healthconnect/cts/device/ExerciseRouteAccessTest.java
deleted file mode 100644
index fae49f2..0000000
--- a/tests/cts/hostsidetests/healthconnect/device/src/android/healthconnect/cts/device/ExerciseRouteAccessTest.java
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * Copyright (C) 2023 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 android.healthconnect.cts.device;
-
-import static android.health.connect.HealthPermissions.WRITE_EXERCISE_ROUTE;
-import static android.healthconnect.cts.device.HealthConnectDeviceTest.APP_A_WITH_READ_WRITE_PERMS;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.READ_RECORDS_SIZE;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.RECORD_IDS;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.SUCCESS;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.insertRecordAs;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.insertSessionNoRouteAs;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.readRecordsAs;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.updateRouteAs;
-import static android.healthconnect.cts.utils.TestUtils.READ_EXERCISE_ROUTE_PERMISSION;
-import static android.healthconnect.cts.utils.TestUtils.deleteAllStagedRemoteData;
-import static android.healthconnect.cts.utils.TestUtils.deleteTestData;
-import static android.healthconnect.cts.utils.TestUtils.getChangeLogToken;
-import static android.healthconnect.cts.utils.TestUtils.getChangeLogs;
-import static android.healthconnect.cts.utils.TestUtils.getExerciseSessionRecord;
-import static android.healthconnect.cts.utils.TestUtils.insertRecords;
-import static android.healthconnect.cts.utils.TestUtils.readRecords;
-
-import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
-
-import static com.android.compatibility.common.util.FeatureUtil.AUTOMOTIVE_FEATURE;
-import static com.android.compatibility.common.util.FeatureUtil.hasSystemFeature;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.UiAutomation;
-import android.health.connect.HealthConnectException;
-import android.health.connect.ReadRecordsRequestUsingFilters;
-import android.health.connect.ReadRecordsRequestUsingIds;
-import android.health.connect.changelog.ChangeLogTokenRequest;
-import android.health.connect.changelog.ChangeLogsRequest;
-import android.health.connect.changelog.ChangeLogsResponse;
-import android.health.connect.datatypes.ExerciseSessionRecord;
-import android.healthconnect.cts.utils.TestUtils.RecordTypeAndRecordIds;
-import android.os.Bundle;
-
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-
-public class ExerciseRouteAccessTest {
-
-    private UiAutomation mAutomation;
-
-    @Before
-    public void setUp() {
-        mAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
-        Assume.assumeFalse(hasSystemFeature(AUTOMOTIVE_FEATURE));
-
-        mAutomation.grantRuntimePermission(
-                APP_A_WITH_READ_WRITE_PERMS.getPackageName(), WRITE_EXERCISE_ROUTE);
-    }
-
-    @After
-    public void tearDown() throws InterruptedException {
-        deleteTestData();
-        deleteAllStagedRemoteData();
-
-        mAutomation.grantRuntimePermission(
-                APP_A_WITH_READ_WRITE_PERMS.getPackageName(), WRITE_EXERCISE_ROUTE);
-    }
-
-    @Test
-    public void readRecords_usingFilters_cannotAccessOtherAppRoute() throws Exception {
-        assertThat(insertRecordAs(APP_A_WITH_READ_WRITE_PERMS).getBoolean(SUCCESS)).isTrue();
-
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
-                                .build());
-
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-        assertThat(records.get(0).getRoute()).isNull();
-    }
-
-    @Test
-    public void readRecords_usingFilters_withReadExerciseRoutePermission_canAccessOtherAppRoute()
-            throws Exception {
-        assertThat(insertRecordAs(APP_A_WITH_READ_WRITE_PERMS).getBoolean(SUCCESS)).isTrue();
-        mAutomation.adoptShellPermissionIdentity(READ_EXERCISE_ROUTE_PERMISSION);
-
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
-                                .build());
-
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-        assertThat(records.get(0).getRoute()).isNotNull();
-    }
-
-    @Test
-    public void readRecords_usingFilters_canAccessOwnRoute() throws Exception {
-        ExerciseSessionRecord record =
-                getExerciseSessionRecord(
-                        getApplicationContext().getPackageName(), 0.0, /* withRoute= */ true);
-        insertRecords(List.of(record), getApplicationContext());
-
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
-                                .build());
-
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-        assertThat(records.get(0).getRoute()).isEqualTo(record.getRoute());
-    }
-
-    @Test
-    public void readRecords_usingFilters_mixedOwnAndOtherAppSession() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-        String otherAppSessionId = getInsertedSessionId(bundle);
-        ExerciseSessionRecord ownSession =
-                getExerciseSessionRecord(
-                        getApplicationContext().getPackageName(), 0.0, /* withRoute= */ true);
-        String ownSessionId =
-                insertRecords(List.of(ownSession), getApplicationContext())
-                        .get(0)
-                        .getMetadata()
-                        .getId();
-
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
-                                .build());
-
-        Map<String, ExerciseSessionRecord> idToRecordMap =
-                records.stream()
-                        .collect(
-                                Collectors.toMap(
-                                        record -> record.getMetadata().getId(),
-                                        Function.identity()));
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(2);
-        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
-        assertThat(idToRecordMap.get(otherAppSessionId).getRoute()).isNull();
-        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
-        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
-    }
-
-    @Test
-    public void readRecords_usingIds_cannotAccessOtherAppRoute() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-        String sessionId = getInsertedSessionId(bundle);
-
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
-                                .addId(sessionId)
-                                .build());
-
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-        assertThat(records.get(0).getRoute()).isNull();
-    }
-
-    @Test
-    public void readRecords_usingIds_withReadExerciseRoutePermission_canAccessOtherAppRoute()
-            throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-        String sessionId = getInsertedSessionId(bundle);
-        mAutomation.adoptShellPermissionIdentity(READ_EXERCISE_ROUTE_PERMISSION);
-
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
-                                .addId(sessionId)
-                                .build());
-
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-        assertThat(records.get(0).getRoute()).isNotNull();
-    }
-
-    @Test
-    public void readRecords_usingIds_canAccessOwnRoute() throws Exception {
-        ExerciseSessionRecord record =
-                getExerciseSessionRecord(
-                        getApplicationContext().getPackageName(), 0.0, /* withRoute= */ true);
-        String sessionId =
-                insertRecords(List.of(record), getApplicationContext())
-                        .get(0)
-                        .getMetadata()
-                        .getId();
-
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
-                                .addId(sessionId)
-                                .build());
-
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-        assertThat(records.get(0).getRoute()).isEqualTo(record.getRoute());
-    }
-
-    @Test
-    public void readRecords_usingIds_mixedOwnAndOtherAppSession() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-        String otherAppSessionId = getInsertedSessionId(bundle);
-        ExerciseSessionRecord ownSession =
-                getExerciseSessionRecord(
-                        getApplicationContext().getPackageName(), 0.0, /* withRoute= */ true);
-        String ownSessionId =
-                insertRecords(List.of(ownSession), getApplicationContext())
-                        .get(0)
-                        .getMetadata()
-                        .getId();
-
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
-                                .addId(otherAppSessionId)
-                                .addId(ownSessionId)
-                                .build());
-
-        Map<String, ExerciseSessionRecord> idToRecordMap =
-                records.stream()
-                        .collect(
-                                Collectors.toMap(
-                                        record -> record.getMetadata().getId(),
-                                        Function.identity()));
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(2);
-        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
-        assertThat(idToRecordMap.get(otherAppSessionId).getRoute()).isNull();
-        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
-        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
-    }
-
-    @Test
-    public void getChangelogs_cannotAccessOtherAppRoute() throws Exception {
-        String token =
-                getChangeLogToken(
-                                new ChangeLogTokenRequest.Builder()
-                                        .addRecordType(ExerciseSessionRecord.class)
-                                        .build(),
-                                getApplicationContext())
-                        .getToken();
-        assertThat(insertRecordAs(APP_A_WITH_READ_WRITE_PERMS).getBoolean(SUCCESS)).isTrue();
-
-        ChangeLogsResponse response =
-                getChangeLogs(
-                        new ChangeLogsRequest.Builder(token).build(), getApplicationContext());
-
-        List<ExerciseSessionRecord> records =
-                response.getUpsertedRecords().stream()
-                        .map(ExerciseSessionRecord.class::cast)
-                        .toList();
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-        assertThat(records.get(0).getRoute()).isNull();
-    }
-
-    @Test
-    public void getChangelogs_withReadExerciseRoutePermission_canAccessOtherAppRoute()
-            throws Exception {
-        String token =
-                getChangeLogToken(
-                                new ChangeLogTokenRequest.Builder()
-                                        .addRecordType(ExerciseSessionRecord.class)
-                                        .build(),
-                                getApplicationContext())
-                        .getToken();
-        assertThat(insertRecordAs(APP_A_WITH_READ_WRITE_PERMS).getBoolean(SUCCESS)).isTrue();
-        mAutomation.adoptShellPermissionIdentity(READ_EXERCISE_ROUTE_PERMISSION);
-
-        ChangeLogsResponse response =
-                getChangeLogs(
-                        new ChangeLogsRequest.Builder(token).build(), getApplicationContext());
-
-        List<ExerciseSessionRecord> records =
-                response.getUpsertedRecords().stream()
-                        .map(ExerciseSessionRecord.class::cast)
-                        .toList();
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-        assertThat(records.get(0).getRoute()).isNotNull();
-    }
-
-    @Test
-    public void getChangelogs_canAccessOwnRoute() throws Exception {
-        String token =
-                getChangeLogToken(
-                                new ChangeLogTokenRequest.Builder()
-                                        .addRecordType(ExerciseSessionRecord.class)
-                                        .build(),
-                                getApplicationContext())
-                        .getToken();
-        ExerciseSessionRecord record =
-                getExerciseSessionRecord(
-                        getApplicationContext().getPackageName(), 0.0, /* withRoute= */ true);
-        insertRecords(List.of(record), getApplicationContext());
-
-        ChangeLogsResponse response =
-                getChangeLogs(
-                        new ChangeLogsRequest.Builder(token).build(), getApplicationContext());
-
-        List<ExerciseSessionRecord> records =
-                response.getUpsertedRecords().stream()
-                        .map(ExerciseSessionRecord.class::cast)
-                        .toList();
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-        assertThat(records.get(0).getRoute()).isEqualTo(record.getRoute());
-    }
-
-    @Test
-    public void getChangelogs_mixedOwnAndOtherAppSession() throws Exception {
-        String token =
-                getChangeLogToken(
-                                new ChangeLogTokenRequest.Builder()
-                                        .addRecordType(ExerciseSessionRecord.class)
-                                        .build(),
-                                getApplicationContext())
-                        .getToken();
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-        String otherAppSessionId = getInsertedSessionId(bundle);
-        ExerciseSessionRecord ownSession =
-                getExerciseSessionRecord(
-                        getApplicationContext().getPackageName(), 0.0, /* withRoute= */ true);
-        String ownSessionId =
-                insertRecords(List.of(ownSession), getApplicationContext())
-                        .get(0)
-                        .getMetadata()
-                        .getId();
-
-        ChangeLogsResponse response =
-                getChangeLogs(
-                        new ChangeLogsRequest.Builder(token).build(), getApplicationContext());
-
-        Map<String, ExerciseSessionRecord> idToRecordMap =
-                response.getUpsertedRecords().stream()
-                        .map(ExerciseSessionRecord.class::cast)
-                        .collect(
-                                Collectors.toMap(
-                                        record -> record.getMetadata().getId(),
-                                        Function.identity()));
-        assertThat(response.getUpsertedRecords()).isNotNull();
-        assertThat(response.getUpsertedRecords()).hasSize(2);
-        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
-        assertThat(idToRecordMap.get(otherAppSessionId).getRoute()).isNull();
-        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
-        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
-    }
-
-    @Test
-    public void testRouteInsert_cannotInsertRouteWithoutPerm() throws Exception {
-        mAutomation.revokeRuntimePermission(
-                APP_A_WITH_READ_WRITE_PERMS.getPackageName(), WRITE_EXERCISE_ROUTE);
-
-        try {
-            insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-            Assert.fail("Should have thrown an Security Exception!");
-        } catch (HealthConnectException e) {
-            assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
-        } finally {
-            mAutomation.grantRuntimePermission(
-                    APP_A_WITH_READ_WRITE_PERMS.getPackageName(), WRITE_EXERCISE_ROUTE);
-        }
-    }
-
-    @Test
-    public void testRouteUpdate_updateRouteWithPerm_noRouteAfterUpdate() throws Exception {
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
-                                .build());
-        assertThat(records).isEmpty();
-
-        assertThat(insertRecordAs(APP_A_WITH_READ_WRITE_PERMS).getBoolean(SUCCESS)).isTrue();
-        records =
-                readRecords(
-                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
-                                .build());
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-
-        assertThat(updateRouteAs(APP_A_WITH_READ_WRITE_PERMS).getBoolean(SUCCESS)).isTrue();
-
-        records =
-                readRecords(
-                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
-                                .build());
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isFalse();
-
-        // Check that the route has been actually deleted, so no exceptions from incorrect record
-        // state.
-        Bundle bundle =
-                readRecordsAs(
-                        APP_A_WITH_READ_WRITE_PERMS,
-                        new ArrayList<>(List.of(ExerciseSessionRecord.class.getName())));
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-        assertThat(bundle.getInt(READ_RECORDS_SIZE)).isEqualTo(1);
-    }
-
-    @Test
-    public void testRouteUpdate_updateRouteWithoutPerm_hasRouteAfterUpdate() throws Exception {
-        assertThat(insertRecordAs(APP_A_WITH_READ_WRITE_PERMS).getBoolean(SUCCESS)).isTrue();
-        mAutomation.revokeRuntimePermission(
-                APP_A_WITH_READ_WRITE_PERMS.getPackageName(), WRITE_EXERCISE_ROUTE);
-
-        updateRouteAs(APP_A_WITH_READ_WRITE_PERMS);
-
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
-                                .build());
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-    }
-
-    @Test
-    public void testRouteUpsert_insertRecordNoRouteWithoutRoutePerm_hasRouteAfterInsert()
-            throws Exception {
-        assertThat(insertRecordAs(APP_A_WITH_READ_WRITE_PERMS).getBoolean(SUCCESS)).isTrue();
-        mAutomation.revokeRuntimePermission(
-                APP_A_WITH_READ_WRITE_PERMS.getPackageName(), WRITE_EXERCISE_ROUTE);
-
-        insertSessionNoRouteAs(APP_A_WITH_READ_WRITE_PERMS);
-
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
-                                .build());
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isTrue();
-    }
-
-    @Test
-    public void testRouteUpsert_insertRecordNoRouteWithRoutePerm_noRouteAfterInsert()
-            throws Exception {
-        assertThat(insertRecordAs(APP_A_WITH_READ_WRITE_PERMS).getBoolean(SUCCESS)).isTrue();
-        insertSessionNoRouteAs(APP_A_WITH_READ_WRITE_PERMS);
-
-        List<ExerciseSessionRecord> records =
-                readRecords(
-                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
-                                .build());
-        assertThat(records).isNotNull();
-        assertThat(records).hasSize(1);
-        assertThat(records.get(0).hasRoute()).isFalse();
-    }
-
-    private static String getInsertedSessionId(Bundle bundle) {
-        List<String> ids =
-                ((List<RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS))
-                        .stream()
-                                .filter(
-                                        it ->
-                                                it.getRecordType()
-                                                        .equals(
-                                                                ExerciseSessionRecord.class
-                                                                        .getName()))
-                                .map(RecordTypeAndRecordIds::getRecordIds)
-                                .flatMap(Collection::stream)
-                                .toList();
-        assertThat(ids).hasSize(1);
-        return ids.get(0);
-    }
-}
diff --git a/tests/cts/hostsidetests/healthconnect/device/src/android/healthconnect/cts/device/HealthConnectDeviceTest.java b/tests/cts/hostsidetests/healthconnect/device/src/android/healthconnect/cts/device/HealthConnectDeviceTest.java
index b6121f8..7905b4e 100644
--- a/tests/cts/hostsidetests/healthconnect/device/src/android/healthconnect/cts/device/HealthConnectDeviceTest.java
+++ b/tests/cts/hostsidetests/healthconnect/device/src/android/healthconnect/cts/device/HealthConnectDeviceTest.java
@@ -16,48 +16,40 @@
 
 package android.healthconnect.cts.device;
 
+import static android.health.connect.datatypes.ExerciseSegmentType.EXERCISE_SEGMENT_TYPE_PAUSE;
 import static android.health.connect.datatypes.ExerciseSessionRecord.EXERCISE_DURATION_TOTAL;
+import static android.health.connect.datatypes.ExerciseSessionType.EXERCISE_SESSION_TYPE_RUNNING;
 import static android.health.connect.datatypes.StepsRecord.STEPS_COUNT_TOTAL;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.CHANGE_LOGS_RESPONSE;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.CHANGE_LOG_TOKEN;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.READ_RECORDS_SIZE;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.RECORD_IDS;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.SUCCESS;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.deleteRecordsAs;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.getChangeLogTokenAs;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.getDataOriginPriorityOrder;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.insertExerciseSessionAs;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.insertRecordAs;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.insertRecordWithAnotherAppPackageName;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.insertRecordWithGivenClientId;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.insertStepsRecordAs;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.readChangeLogsUsingDataOriginFiltersAs;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.readRecordsAs;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.readRecordsUsingDataOriginFiltersAs;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.updateRecordsAs;
+import static android.healthconnect.cts.utils.DataFactory.getDataOrigin;
+import static android.healthconnect.cts.utils.DataFactory.getDataOrigins;
+import static android.healthconnect.cts.utils.DataFactory.getEmptyMetadata;
+import static android.healthconnect.cts.utils.DataFactory.getMetadata;
+import static android.healthconnect.cts.utils.DataFactory.getMetadataForClientId;
+import static android.healthconnect.cts.utils.DataFactory.getMetadataForId;
+import static android.healthconnect.cts.utils.PermissionHelper.getGrantedHealthPermissions;
+import static android.healthconnect.cts.utils.PermissionHelper.grantPermission;
+import static android.healthconnect.cts.utils.PermissionHelper.revokeAndThenGrantHealthPermissions;
+import static android.healthconnect.cts.utils.PermissionHelper.revokeHealthPermissions;
+import static android.healthconnect.cts.utils.PermissionHelper.revokePermission;
 import static android.healthconnect.cts.utils.TestUtils.deleteAllStagedRemoteData;
 import static android.healthconnect.cts.utils.TestUtils.deleteTestData;
 import static android.healthconnect.cts.utils.TestUtils.fetchDataOriginsPriorityOrder;
 import static android.healthconnect.cts.utils.TestUtils.getAggregateResponse;
 import static android.healthconnect.cts.utils.TestUtils.getApplicationInfo;
-import static android.healthconnect.cts.utils.TestUtils.getGrantedHealthPermissions;
-import static android.healthconnect.cts.utils.TestUtils.getInstantTime;
-import static android.healthconnect.cts.utils.TestUtils.grantPermission;
+import static android.healthconnect.cts.utils.TestUtils.getRecordIdFilters;
 import static android.healthconnect.cts.utils.TestUtils.insertRecordsForPriority;
 import static android.healthconnect.cts.utils.TestUtils.readRecords;
-import static android.healthconnect.cts.utils.TestUtils.revokeAndThenGrantHealthPermissions;
-import static android.healthconnect.cts.utils.TestUtils.revokeHealthPermissions;
-import static android.healthconnect.cts.utils.TestUtils.revokePermission;
 import static android.healthconnect.cts.utils.TestUtils.updateDataOriginPriorityOrder;
 import static android.healthconnect.cts.utils.TestUtils.verifyDeleteRecords;
-
-import static com.android.compatibility.common.util.FeatureUtil.AUTOMOTIVE_FEATURE;
-import static com.android.compatibility.common.util.FeatureUtil.hasSystemFeature;
+import static android.healthconnect.cts.utils.TestUtils.yesterdayAt;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.fail;
 
+import static java.time.Duration.ofMinutes;
+
 import android.app.UiAutomation;
 import android.content.Context;
 import android.health.connect.AggregateRecordsRequest;
@@ -70,37 +62,39 @@
 import android.health.connect.RecordIdFilter;
 import android.health.connect.TimeInstantRangeFilter;
 import android.health.connect.UpdateDataOriginPriorityOrderRequest;
+import android.health.connect.changelog.ChangeLogTokenRequest;
+import android.health.connect.changelog.ChangeLogsRequest;
 import android.health.connect.changelog.ChangeLogsResponse;
 import android.health.connect.datatypes.AggregationType;
+import android.health.connect.datatypes.AppInfo;
+import android.health.connect.datatypes.BasalMetabolicRateRecord;
 import android.health.connect.datatypes.DataOrigin;
+import android.health.connect.datatypes.ExerciseSegment;
 import android.health.connect.datatypes.ExerciseSessionRecord;
 import android.health.connect.datatypes.HeartRateRecord;
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.StepsRecord;
+import android.health.connect.datatypes.units.Power;
+import android.healthconnect.cts.lib.TestAppProxy;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
-import android.os.Bundle;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
-import com.android.cts.install.lib.TestApp;
-
 import org.junit.After;
-import org.junit.Assert;
-import org.junit.Assume;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.time.Duration;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Optional;
-import java.util.Set;
 import java.util.stream.Collectors;
 
 @RunWith(AndroidJUnit4.class)
@@ -111,37 +105,27 @@
     private static final int ASYNC_RETRIES = 3;
     private static final int ASYNC_RETRY_DELAY_MILLIS = 500;
 
-    static final TestApp APP_A_WITH_READ_WRITE_PERMS =
-            new TestApp(
-                    "TestAppA",
-                    "android.healthconnect.cts.testapp.readWritePerms.A",
-                    VERSION_CODE,
-                    false,
-                    "CtsHealthConnectTestAppA.apk");
+    private static final Instant NOW = Instant.now().truncatedTo(ChronoUnit.MILLIS);
 
-    private static final TestApp APP_B_WITH_READ_WRITE_PERMS =
-            new TestApp(
-                    "TestAppB",
-                    "android.healthconnect.cts.testapp.readWritePerms.B",
-                    VERSION_CODE,
-                    false,
-                    "CtsHealthConnectTestAppB.apk");
+    private static final List<Record> TEST_RECORDS =
+            List.of(
+                    getStepsRecord(getEmptyMetadata()),
+                    getHeartRateRecord(getEmptyMetadata()),
+                    getBasalMetabolicRateRecord(getEmptyMetadata()),
+                    getExerciseSessionRecord(getEmptyMetadata()));
 
-    private static final TestApp APP_WITH_WRITE_PERMS_ONLY =
-            new TestApp(
-                    "TestAppC",
-                    "android.healthconnect.cts.testapp.writePermsOnly",
-                    VERSION_CODE,
-                    false,
-                    "CtsHealthConnectTestAppWithWritePermissionsOnly.apk");
+    private static final TestAppProxy APP_A_WITH_READ_WRITE_PERMS =
+            TestAppProxy.forPackageName("android.healthconnect.cts.testapp.readWritePerms.A");
 
-    private static final TestApp APP_WITH_DATA_MANAGE_PERMS_ONLY =
-            new TestApp(
-                    "TestAppD",
-                    "android.healthconnect.cts.testapp.data.manage.permissions",
-                    VERSION_CODE,
-                    false,
-                    "CtsHealthConnectTestAppWithDataManagePermission.apk");
+    private static final TestAppProxy APP_B_WITH_READ_WRITE_PERMS =
+            TestAppProxy.forPackageName("android.healthconnect.cts.testapp.readWritePerms.B");
+
+    private static final TestAppProxy APP_WITH_WRITE_PERMS_ONLY =
+            TestAppProxy.forPackageName("android.healthconnect.cts.testapp.writePermsOnly");
+
+    private static final TestAppProxy APP_WITH_DATA_MANAGE_PERMS_ONLY =
+            TestAppProxy.forPackageName(
+                    "android.healthconnect.cts.testapp.data.manage.permissions");
 
     private static final String STEPS_1000_CLIENT_ID = "client-id-1";
     private static final String STEPS_2000_CLIENT_ID = "client-id-2";
@@ -166,9 +150,13 @@
 
     private Context mContext;
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() {
-        Assume.assumeFalse(hasSystemFeature(AUTOMOTIVE_FEATURE));
         mContext = ApplicationProvider.getApplicationContext();
     }
 
@@ -180,173 +168,138 @@
 
     @Test
     public void testAppWithNormalReadWritePermCanInsertRecord() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        StepsRecord record = getStepsRecord(getEmptyMetadata());
+        APP_A_WITH_READ_WRITE_PERMS.insertRecords(record);
     }
 
     @Test
     public void testAnAppCantDeleteAnotherAppEntry() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        StepsRecord record = getStepsRecord(getEmptyMetadata());
+        String recordId = APP_A_WITH_READ_WRITE_PERMS.insertRecords(record).get(0);
+        RecordIdFilter recordIdFilter = RecordIdFilter.fromId(StepsRecord.class, recordId);
 
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () -> APP_B_WITH_READ_WRITE_PERMS.deleteRecords(recordIdFilter));
 
-        try {
-            deleteRecordsAs(APP_B_WITH_READ_WRITE_PERMS, listOfRecordIdsAndClass);
-            Assert.fail("Should have thrown an Invalid Argument Exception!");
-        } catch (HealthConnectException e) {
-
-            assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_INVALID_ARGUMENT);
-        }
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_INVALID_ARGUMENT);
     }
 
     @Test
     public void testAnAppCantUpdateAnotherAppEntry() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        StepsRecord record = getStepsRecord(getEmptyMetadata());
+        String recordId = APP_A_WITH_READ_WRITE_PERMS.insertRecords(record).get(0);
+        StepsRecord updatedRecord = getStepsRecord(getMetadataForId(recordId));
 
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () -> APP_B_WITH_READ_WRITE_PERMS.updateRecords(updatedRecord));
 
-        try {
-            updateRecordsAs(APP_B_WITH_READ_WRITE_PERMS, listOfRecordIdsAndClass);
-            Assert.fail("Should have thrown an Invalid Argument Exception!");
-        } catch (HealthConnectException e) {
-            assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_INVALID_ARGUMENT);
-        }
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_INVALID_ARGUMENT);
     }
 
     @Test
     public void testDataOriginGetsOverriddenBySelfPackageName() throws Exception {
-        Bundle bundle =
-                insertRecordWithAnotherAppPackageName(
-                        APP_A_WITH_READ_WRITE_PERMS, APP_B_WITH_READ_WRITE_PERMS);
+        ExerciseSessionRecord record =
+                getExerciseSessionRecord(getMetadata(getDataOrigin("ignored.package.name")));
+        String recordId = APP_A_WITH_READ_WRITE_PERMS.insertRecords(record).get(0);
 
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
+        List<ExerciseSessionRecord> records =
+                readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
 
-        for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds : listOfRecordIdsAndClass) {
-            Class<? extends Record> recordType =
-                    (Class<? extends Record>) Class.forName(recordTypeAndRecordIds.getRecordType());
-            if (!recordType.equals(ExerciseSessionRecord.class)) {
-                // skip other record types since we don't have read permissions for these.
-                continue;
-            }
-            List<Record> records =
-                    (List<Record>)
-                            readRecords(
-                                    new ReadRecordsRequestUsingFilters.Builder<>(recordType)
-                                            .build());
-            assertThat(records).isNotEmpty();
-            for (Record record : records) {
-                assertThat(record.getMetadata().getDataOrigin().getPackageName())
-                        .isEqualTo(APP_A_WITH_READ_WRITE_PERMS.getPackageName());
-            }
-        }
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).getMetadata())
+                .isEqualTo(
+                        new Metadata.Builder()
+                                .setId(recordId)
+                                .setDataOrigin(
+                                        getDataOrigin(APP_A_WITH_READ_WRITE_PERMS.getPackageName()))
+                                .build());
     }
 
     @Test
     public void testAppWithWritePermsOnly_readOwnData_success() throws Exception {
-        Bundle bundle = insertRecordAs(APP_WITH_WRITE_PERMS_ONLY);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        StepsRecord record = getStepsRecord(getEmptyMetadata());
+        String recordId = APP_WITH_WRITE_PERMS_ONLY.insertRecords(record).get(0);
 
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
+        List<StepsRecord> records =
+                APP_WITH_WRITE_PERMS_ONLY.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class)
+                                .addDataOrigins(
+                                        getDataOrigin(APP_WITH_WRITE_PERMS_ONLY.getPackageName()))
+                                .build());
 
-        ArrayList<String> recordClassesToRead = new ArrayList<>();
-        for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds : listOfRecordIdsAndClass) {
-            recordClassesToRead.add(recordTypeAndRecordIds.getRecordType());
-        }
-
-        bundle =
-                readRecordsAs(
-                        APP_WITH_WRITE_PERMS_ONLY,
-                        recordClassesToRead,
-                        /* dataOriginFilterPackageNames= */ Optional.of(
-                                List.of(APP_WITH_WRITE_PERMS_ONLY.getPackageName())));
-        assertThat(bundle.getInt(READ_RECORDS_SIZE)).isEqualTo(listOfRecordIdsAndClass.size());
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0))
+                .isEqualTo(
+                        getStepsRecord(
+                                getMetadataForId(
+                                        recordId,
+                                        getDataOrigin(
+                                                APP_WITH_WRITE_PERMS_ONLY.getPackageName()))));
     }
 
     @Test
     public void testAppWithWritePermsOnly_readDataFromAllApps_throwsError() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        StepsRecord record = getStepsRecord(getEmptyMetadata());
+        APP_A_WITH_READ_WRITE_PERMS.insertRecords(record).get(0);
 
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
-
-        ArrayList<String> recordClassesToRead = new ArrayList<>();
-        for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds : listOfRecordIdsAndClass) {
-            recordClassesToRead.add(recordTypeAndRecordIds.getRecordType());
-        }
-
-        try {
-            bundle =
-                    readRecordsAs(
-                            APP_WITH_WRITE_PERMS_ONLY,
-                            recordClassesToRead,
-                            // empty data implies all data is requested
-                            /* dataOriginFilterPackageNames= */ Optional.of(List.of()));
-            fail("Expected to fail with HealthConnectException but didn't");
-        } catch (Exception e) {
-            assertThat(e).isInstanceOf(HealthConnectException.class);
-            assertThat(((HealthConnectException) e).getErrorCode())
-                    .isEqualTo(HealthConnectException.ERROR_SECURITY);
-        }
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () ->
+                                APP_WITH_WRITE_PERMS_ONLY.readRecords(
+                                        new ReadRecordsRequestUsingFilters.Builder<>(
+                                                        StepsRecord.class)
+                                                .build()));
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
     }
 
     @Test
     public void testAppWithWritePermsOnly_readDataFromOtherApps_throwsError() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        StepsRecord record = getStepsRecord(getEmptyMetadata());
+        APP_A_WITH_READ_WRITE_PERMS.insertRecords(record);
 
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
-
-        ArrayList<String> recordClassesToRead = new ArrayList<>();
-        for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds : listOfRecordIdsAndClass) {
-            recordClassesToRead.add(recordTypeAndRecordIds.getRecordType());
-        }
-
-        try {
-            readRecordsAs(
-                    APP_WITH_WRITE_PERMS_ONLY,
-                    recordClassesToRead,
-                    /* dataOriginFilterPackageNames= */ Optional.of(
-                            List.of(
-                                    APP_WITH_WRITE_PERMS_ONLY.getPackageName(),
-                                    APP_A_WITH_READ_WRITE_PERMS.getPackageName())));
-            fail("Expected to fail with HealthConnectException but didn't");
-        } catch (Exception e) {
-            assertThat(e).isInstanceOf(HealthConnectException.class);
-            assertThat(((HealthConnectException) e).getErrorCode())
-                    .isEqualTo(HealthConnectException.ERROR_SECURITY);
-        }
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () ->
+                                APP_WITH_WRITE_PERMS_ONLY.readRecords(
+                                        new ReadRecordsRequestUsingFilters.Builder<>(
+                                                        StepsRecord.class)
+                                                .addDataOrigins(
+                                                        getDataOrigin(
+                                                                APP_WITH_WRITE_PERMS_ONLY
+                                                                        .getPackageName()))
+                                                .addDataOrigins(
+                                                        getDataOrigin(
+                                                                APP_A_WITH_READ_WRITE_PERMS
+                                                                        .getPackageName()))
+                                                .build()));
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
     }
 
     @Test
     public void testAppWithWritePermsOnly_readDataByIdForOwnApp_success() throws Exception {
-        Bundle bundle =
-                insertStepsRecordAs(APP_A_WITH_READ_WRITE_PERMS, "01:00 PM", "03:00 PM", 1000);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-        List<Record> writtenRecords = TestUtils.insertRecords(List.of(STEPS_1000, STEPS_2000));
-        List<String> recordIds =
-                writtenRecords.stream()
-                        .map(record -> record.getMetadata().getId())
-                        .collect(Collectors.toList());
+        List<Record> ownRecords = TestUtils.insertRecords(List.of(STEPS_1000, STEPS_2000));
+        List<String> ownRecordIds =
+                ownRecords.stream().map(record -> record.getMetadata().getId()).toList();
 
         List<Record> readRecords =
                 TestUtils.readRecords(
                         new ReadRecordsRequestUsingIds.Builder(StepsRecord.class)
-                                .addId(recordIds.get(0))
-                                .addId(recordIds.get(1))
+                                .addId(ownRecordIds.get(0))
+                                .addId(ownRecordIds.get(1))
                                 .build());
 
         assertThat(
                         readRecords.stream()
                                 .map(record -> record.getMetadata().getClientRecordId())
-                                .collect(Collectors.toList()))
+                                .toList())
                 .containsExactly(STEPS_1000_CLIENT_ID, STEPS_2000_CLIENT_ID);
     }
 
@@ -354,25 +307,18 @@
     @Test
     public void testAppWithWritePermsOnly_readDataByIdForOtherApps_filtersOutOtherAppData()
             throws Exception {
-        Bundle bundle =
-                insertStepsRecordAs(APP_A_WITH_READ_WRITE_PERMS, "01:00 PM", "03:00 PM", 1000);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-        String otherAppRecordId =
-                ((List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS))
-                        .get(0)
-                        .getRecordIds()
-                        .get(0);
-        List<Record> writtenRecords = TestUtils.insertRecords(List.of(STEPS_1000, STEPS_2000));
-        List<String> recordIds =
-                writtenRecords.stream()
-                        .map(record -> record.getMetadata().getId())
-                        .collect(Collectors.toList());
+        StepsRecord otherAppRecord = getStepsRecord(getEmptyMetadata());
+        String otherAppRecordId = APP_A_WITH_READ_WRITE_PERMS.insertRecords(otherAppRecord).get(0);
+
+        List<Record> ownRecords = TestUtils.insertRecords(List.of(STEPS_1000, STEPS_2000));
+        List<String> ownRecordIds =
+                ownRecords.stream().map(record -> record.getMetadata().getId()).toList();
 
         List<Record> readRecords =
                 TestUtils.readRecords(
                         new ReadRecordsRequestUsingIds.Builder(StepsRecord.class)
-                                .addId(recordIds.get(0))
-                                .addId(recordIds.get(1))
+                                .addId(ownRecordIds.get(0))
+                                .addId(ownRecordIds.get(1))
                                 .addId(otherAppRecordId)
                                 .build());
 
@@ -501,144 +447,119 @@
     }
 
     @Test
-    public void testAppWithManageHealthDataPermsOnlyCantInsertRecords() throws Exception {
-        try {
-            insertRecordAs(APP_WITH_DATA_MANAGE_PERMS_ONLY);
-            Assert.fail("Should have thrown Exception while inserting records!");
-        } catch (HealthConnectException e) {
-            assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
-        }
+    public void testAppWithManageHealthDataPermsOnlyCantInsertRecords() {
+        StepsRecord record = getStepsRecord(getEmptyMetadata());
+
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () -> APP_WITH_DATA_MANAGE_PERMS_ONLY.insertRecords(record));
+
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
     }
 
     @Test
     public void testAppWithManageHealthDataPermsOnlyCantUpdateRecords() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        StepsRecord record = getStepsRecord(getEmptyMetadata());
+        String recordId = APP_WITH_WRITE_PERMS_ONLY.insertRecords(record).get(0);
+        StepsRecord updatedRecord = getStepsRecord(getMetadataForId(recordId));
 
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () -> APP_WITH_DATA_MANAGE_PERMS_ONLY.updateRecords(updatedRecord));
 
-        try {
-            updateRecordsAs(APP_WITH_DATA_MANAGE_PERMS_ONLY, listOfRecordIdsAndClass);
-            Assert.fail("Should have thrown Health Connect Exception!");
-        } catch (HealthConnectException e) {
-            assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
-        }
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
     }
 
     @Test
     public void testTwoAppsCanUseSameClientRecordIdsToInsert() throws Exception {
-        final double clientId = Math.random();
-        Bundle bundle = insertRecordWithGivenClientId(APP_A_WITH_READ_WRITE_PERMS, clientId);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        StepsRecord record = getStepsRecord(getMetadataForClientId("common.client.id"));
 
-        bundle = insertRecordWithGivenClientId(APP_B_WITH_READ_WRITE_PERMS, clientId);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        APP_A_WITH_READ_WRITE_PERMS.insertRecords(record);
+        APP_B_WITH_READ_WRITE_PERMS.insertRecords(record);
     }
 
     @Test
     public void testAppCanReadRecordsUsingDataOriginFilters() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        APP_A_WITH_READ_WRITE_PERMS.insertRecords(TEST_RECORDS);
 
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
+        List<BasalMetabolicRateRecord> basalMetabolicRateRecords =
+                APP_A_WITH_READ_WRITE_PERMS.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(BasalMetabolicRateRecord.class)
+                                .build());
+        List<ExerciseSessionRecord> exerciseSessionRecords =
+                APP_A_WITH_READ_WRITE_PERMS.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+        List<HeartRateRecord> heartRateRecords =
+                APP_A_WITH_READ_WRITE_PERMS.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(HeartRateRecord.class)
+                                .build());
+        List<StepsRecord> stepsRecords =
+                APP_A_WITH_READ_WRITE_PERMS.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class).build());
 
-        int noOfRecordsInsertedByAppA = 0;
-        Set<String> recordClassesToReadSet = new HashSet<>();
-        for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds : listOfRecordIdsAndClass) {
-            noOfRecordsInsertedByAppA += recordTypeAndRecordIds.getRecordIds().size();
-            recordClassesToReadSet.add(recordTypeAndRecordIds.getRecordType());
-        }
-
-        bundle = insertRecordAs(APP_B_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-
-        listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
-
-        for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds : listOfRecordIdsAndClass) {
-            recordClassesToReadSet.add(recordTypeAndRecordIds.getRecordType());
-        }
-
-        ArrayList<String> recordClassesToRead = new ArrayList<>();
-        for (String recordClass : recordClassesToReadSet) {
-            recordClassesToRead.add(recordClass);
-        }
-        bundle =
-                readRecordsUsingDataOriginFiltersAs(
-                        APP_A_WITH_READ_WRITE_PERMS, recordClassesToRead);
-        assertThat(bundle.getInt(READ_RECORDS_SIZE)).isEqualTo(noOfRecordsInsertedByAppA);
+        assertThat(basalMetabolicRateRecords).hasSize(1);
+        assertThat(exerciseSessionRecords).hasSize(1);
+        assertThat(heartRateRecords).hasSize(1);
+        assertThat(stepsRecords).hasSize(1);
     }
 
     @Test
     public void testAppCanReadChangeLogsUsingDataOriginFilters() throws Exception {
-        Bundle bundle =
-                getChangeLogTokenAs(
-                        APP_B_WITH_READ_WRITE_PERMS,
-                        APP_A_WITH_READ_WRITE_PERMS.getPackageName(),
-                        null);
-        String changeLogTokenForAppB = bundle.getString(CHANGE_LOG_TOKEN);
+        String changeLogTokenForAppB =
+                APP_B_WITH_READ_WRITE_PERMS.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addDataOriginFilter(
+                                        getDataOrigin(APP_A_WITH_READ_WRITE_PERMS.getPackageName()))
+                                .build());
+        String changeLogTokenForAppA =
+                APP_A_WITH_READ_WRITE_PERMS.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addDataOriginFilter(
+                                        getDataOrigin(APP_B_WITH_READ_WRITE_PERMS.getPackageName()))
+                                .build());
 
-        bundle =
-                getChangeLogTokenAs(
-                        APP_A_WITH_READ_WRITE_PERMS,
-                        APP_B_WITH_READ_WRITE_PERMS.getPackageName(),
-                        null);
-        String changeLogTokenForAppA = bundle.getString(CHANGE_LOG_TOKEN);
+        List<Record> recordsA =
+                List.of(
+                        getStepsRecord(getEmptyMetadata()),
+                        getHeartRateRecord(getEmptyMetadata()),
+                        getBasalMetabolicRateRecord(getEmptyMetadata()));
 
-        bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        List<String> recordIdsA = APP_A_WITH_READ_WRITE_PERMS.insertRecords(recordsA);
 
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
+        List<Record> updatedRecordsA =
+                List.of(
+                        getStepsRecord(getMetadataForId(recordIdsA.get(0))),
+                        getHeartRateRecord(getMetadataForId(recordIdsA.get(1))),
+                        getBasalMetabolicRateRecord(getMetadataForId(recordIdsA.get(2))));
+        APP_A_WITH_READ_WRITE_PERMS.updateRecords(updatedRecordsA);
 
-        List<String> listOfRecordIdsInsertedByAppA = new ArrayList<>();
-        int noOfRecordsInsertedByAppA = 0;
-        for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds : listOfRecordIdsAndClass) {
-            noOfRecordsInsertedByAppA += recordTypeAndRecordIds.getRecordIds().size();
-            listOfRecordIdsInsertedByAppA.addAll(recordTypeAndRecordIds.getRecordIds());
-        }
+        List<String> bRecordIds = APP_B_WITH_READ_WRITE_PERMS.insertRecords(TEST_RECORDS);
 
-        updateRecordsAs(APP_A_WITH_READ_WRITE_PERMS, listOfRecordIdsAndClass);
+        APP_B_WITH_READ_WRITE_PERMS.deleteRecords(getRecordIdFilters(bRecordIds, TEST_RECORDS));
 
-        bundle = insertRecordAs(APP_B_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        ChangeLogsResponse response =
+                APP_B_WITH_READ_WRITE_PERMS.getChangeLogs(
+                        new ChangeLogsRequest.Builder(changeLogTokenForAppB).build());
 
-        listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
-
-        int noOfRecordsInsertedByAppB = 0;
-        for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds : listOfRecordIdsAndClass) {
-            noOfRecordsInsertedByAppB += recordTypeAndRecordIds.getRecordIds().size();
-        }
-
-        deleteRecordsAs(APP_B_WITH_READ_WRITE_PERMS, listOfRecordIdsAndClass);
-
-        bundle =
-                readChangeLogsUsingDataOriginFiltersAs(
-                        APP_B_WITH_READ_WRITE_PERMS, changeLogTokenForAppB);
-
-        ChangeLogsResponse response = bundle.getParcelable(CHANGE_LOGS_RESPONSE);
-
-        assertThat(response.getUpsertedRecords()).hasSize(noOfRecordsInsertedByAppA);
+        assertThat(response.getUpsertedRecords()).hasSize(recordsA.size());
         assertThat(
                         response.getUpsertedRecords().stream()
                                 .map(Record::getMetadata)
                                 .map(Metadata::getId)
                                 .toList())
-                .containsExactlyElementsIn(listOfRecordIdsInsertedByAppA);
+                .containsExactlyElementsIn(recordIdsA);
 
         assertThat(response.getDeletedLogs()).isEmpty();
 
-        bundle =
-                readChangeLogsUsingDataOriginFiltersAs(
-                        APP_A_WITH_READ_WRITE_PERMS, changeLogTokenForAppA);
-
-        response = bundle.getParcelable(CHANGE_LOGS_RESPONSE);
+        response =
+                APP_A_WITH_READ_WRITE_PERMS.getChangeLogs(
+                        new ChangeLogsRequest.Builder(changeLogTokenForAppA).build());
 
         assertThat(response.getUpsertedRecords()).isEmpty();
-        assertThat(response.getDeletedLogs()).hasSize(noOfRecordsInsertedByAppB);
+        assertThat(response.getDeletedLogs()).hasSize(TEST_RECORDS.size());
     }
 
     @Test
@@ -650,8 +571,8 @@
                 fetchDataOriginsPriorityOrder(HealthDataCategory.ACTIVITY)
                         .getDataOriginsPriorityOrder()
                         .stream()
-                        .map(dataOrigin -> dataOrigin.getPackageName())
-                        .collect(Collectors.toList());
+                        .map(DataOrigin::getPackageName)
+                        .toList();
 
         List<String> healthPerms =
                 getGrantedHealthPermissions(APP_A_WITH_READ_WRITE_PERMS.getPackageName());
@@ -667,8 +588,8 @@
                 fetchDataOriginsPriorityOrder(HealthDataCategory.ACTIVITY)
                         .getDataOriginsPriorityOrder()
                         .stream()
-                        .map(dataOrigin -> dataOrigin.getPackageName())
-                        .collect(Collectors.toList());
+                        .map(DataOrigin::getPackageName)
+                        .toList();
 
         assertThat(newPriorityList).hasSize(oldPriorityList.size() + 1);
         assertThat(newPriorityList).contains(APP_A_WITH_READ_WRITE_PERMS.getPackageName());
@@ -808,79 +729,35 @@
 
     @Test
     public void testAppWithManageHealthDataPermsCanReadAnotherAppEntry() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
-
-        ArrayList<String> recordClassesToRead = new ArrayList<>();
-        for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds : listOfRecordIdsAndClass) {
-            recordClassesToRead.add(recordTypeAndRecordIds.getRecordType());
-        }
-
+        StepsRecord record = getStepsRecord(getEmptyMetadata());
+        APP_A_WITH_READ_WRITE_PERMS.insertRecords(record);
         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         uiAutomation.adoptShellPermissionIdentity(MANAGE_HEALTH_DATA);
-        int recordsSize = 0;
-        try {
-            for (String recordClass : recordClassesToRead) {
-                List<? extends Record> recordsRead =
-                        readRecords(
-                                new ReadRecordsRequestUsingFilters.Builder<>(
-                                                (Class<? extends Record>)
-                                                        Class.forName(recordClass))
-                                        .build(),
-                                ApplicationProvider.getApplicationContext());
 
-                recordsSize += recordsRead.size();
-            }
-        } catch (Exception e) {
-            Assert.fail(
-                    "App with MANAGE_HEALTH_DATA  permission should have read entries of another"
-                            + " app!");
-        }
-        assertThat(recordsSize).isNotEqualTo(0);
+        List<StepsRecord> recordsRead =
+                readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class).build(),
+                        ApplicationProvider.getApplicationContext());
+
+        assertThat(recordsRead).hasSize(1);
     }
 
     @Test
     public void testAppWithManageHealthDataPermsCanDeleteAnotherAppEntry() throws Exception {
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-
-        List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass =
-                (List<TestUtils.RecordTypeAndRecordIds>) bundle.getSerializable(RECORD_IDS);
-
-        List<RecordIdFilter> recordIdFilters = new ArrayList<>();
-        for (TestUtils.RecordTypeAndRecordIds recordTypeAndRecordIds : listOfRecordIdsAndClass) {
-            for (String recordId : recordTypeAndRecordIds.getRecordIds()) {
-                recordIdFilters.add(
-                        RecordIdFilter.fromId(
-                                (Class<? extends Record>)
-                                        Class.forName(recordTypeAndRecordIds.getRecordType()),
-                                recordId));
-            }
-        }
-
+        StepsRecord record = getStepsRecord(getEmptyMetadata());
+        String recordId = APP_A_WITH_READ_WRITE_PERMS.insertRecords(record).get(0);
         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
         uiAutomation.adoptShellPermissionIdentity(MANAGE_HEALTH_DATA);
-        try {
-            verifyDeleteRecords(recordIdFilters, ApplicationProvider.getApplicationContext());
-        } catch (Exception e) {
-            Assert.fail(
-                    "App with MANAGE_HEALTH_DATA  permission should have deleted data from other"
-                            + " app!");
-        }
+
+        verifyDeleteRecords(List.of(RecordIdFilter.fromId(StepsRecord.class, recordId)));
     }
 
     @Test
     public void testToVerifyGetContributorApplicationsInfo() throws Exception {
         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
 
-        Bundle bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-
-        bundle = insertRecordAs(APP_B_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        APP_A_WITH_READ_WRITE_PERMS.insertRecords(TEST_RECORDS);
+        APP_B_WITH_READ_WRITE_PERMS.insertRecords(TEST_RECORDS);
 
         List<String> pkgNameList =
                 List.of(
@@ -893,9 +770,7 @@
         // finishes (or we run out of retries).
         for (int i = 1; i <= ASYNC_RETRIES; i++) {
             List<String> appInfoList =
-                    getApplicationInfo().stream()
-                            .map(appInfo -> appInfo.getPackageName())
-                            .collect(Collectors.toList());
+                    getApplicationInfo().stream().map(AppInfo::getPackageName).toList();
 
             try {
                 assertThat(appInfoList).containsAtLeastElementsIn(pkgNameList);
@@ -915,39 +790,51 @@
             throws Exception {
         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
 
-        revokeAndThenGrantHealthPermissions(APP_A_WITH_READ_WRITE_PERMS);
-        revokeAndThenGrantHealthPermissions(APP_B_WITH_READ_WRITE_PERMS);
+        revokeAndThenGrantHealthPermissions(APP_A_WITH_READ_WRITE_PERMS.getPackageName());
+        revokeAndThenGrantHealthPermissions(APP_B_WITH_READ_WRITE_PERMS.getPackageName());
 
         List<DataOrigin> dataOriginPrioOrder =
-                getDataOriginPriorityOrder(
-                        APP_A_WITH_READ_WRITE_PERMS, APP_B_WITH_READ_WRITE_PERMS);
+                getDataOrigins(
+                        APP_A_WITH_READ_WRITE_PERMS.getPackageName(),
+                        APP_B_WITH_READ_WRITE_PERMS.getPackageName());
 
         uiAutomation.adoptShellPermissionIdentity(MANAGE_HEALTH_DATA);
         List<String> priorityList =
                 fetchDataOriginsPriorityOrder(HealthDataCategory.ACTIVITY)
                         .getDataOriginsPriorityOrder()
                         .stream()
-                        .map(dataOrigin -> dataOrigin.getPackageName())
-                        .collect(Collectors.toList());
+                        .map(DataOrigin::getPackageName)
+                        .toList();
 
         assertThat(
                         priorityList.equals(
                                 dataOriginPrioOrder.stream()
-                                        .map(dataOrigin -> dataOrigin.getPackageName())
-                                        .collect(Collectors.toList())))
+                                        .map(DataOrigin::getPackageName)
+                                        .toList()))
                 .isTrue();
 
-        Bundle bundle =
-                insertStepsRecordAs(APP_A_WITH_READ_WRITE_PERMS, "01:00 PM", "03:00 PM", 1000);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-        bundle = insertStepsRecordAs(APP_B_WITH_READ_WRITE_PERMS, "02:00 PM", "04:00 PM", 2000);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        StepsRecord stepsRecordA =
+                new StepsRecord.Builder(
+                                getEmptyMetadata(),
+                                yesterdayAt("13:00"),
+                                yesterdayAt("15:00"),
+                                1000)
+                        .build();
+        APP_A_WITH_READ_WRITE_PERMS.insertRecords(stepsRecordA);
+        StepsRecord stepsRecordB =
+                new StepsRecord.Builder(
+                                getEmptyMetadata(),
+                                yesterdayAt("14:00"),
+                                yesterdayAt("16:00"),
+                                2000)
+                        .build();
+        APP_B_WITH_READ_WRITE_PERMS.insertRecords(stepsRecordB);
 
         AggregateRecordsRequest<Long> aggregateRecordsRequest =
                 new AggregateRecordsRequest.Builder<Long>(
                                 new TimeInstantRangeFilter.Builder()
-                                        .setStartTime(getInstantTime("01:00 PM"))
-                                        .setEndTime(getInstantTime("04:00 PM"))
+                                        .setStartTime(yesterdayAt("13:00"))
+                                        .setEndTime(yesterdayAt("16:00"))
                                         .build())
                         .addAggregationType(STEPS_COUNT_TOTAL)
                         .build();
@@ -960,8 +847,9 @@
         assertThat(oldResponse.get(STEPS_COUNT_TOTAL)).isEqualTo(2000);
 
         dataOriginPrioOrder =
-                getDataOriginPriorityOrder(
-                        APP_B_WITH_READ_WRITE_PERMS, APP_A_WITH_READ_WRITE_PERMS);
+                getDataOrigins(
+                        APP_B_WITH_READ_WRITE_PERMS.getPackageName(),
+                        APP_A_WITH_READ_WRITE_PERMS.getPackageName());
 
         uiAutomation.adoptShellPermissionIdentity(MANAGE_HEALTH_DATA);
         updateDataOriginPriorityOrder(
@@ -993,46 +881,59 @@
             throws Exception {
         UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
 
-        revokeAndThenGrantHealthPermissions(APP_A_WITH_READ_WRITE_PERMS);
-        revokeAndThenGrantHealthPermissions(APP_B_WITH_READ_WRITE_PERMS);
+        revokeAndThenGrantHealthPermissions(APP_A_WITH_READ_WRITE_PERMS.getPackageName());
+        revokeAndThenGrantHealthPermissions(APP_B_WITH_READ_WRITE_PERMS.getPackageName());
 
         List<DataOrigin> dataOriginPrioOrder =
-                getDataOriginPriorityOrder(
-                        APP_A_WITH_READ_WRITE_PERMS, APP_B_WITH_READ_WRITE_PERMS);
+                getDataOrigins(
+                        APP_A_WITH_READ_WRITE_PERMS.getPackageName(),
+                        APP_B_WITH_READ_WRITE_PERMS.getPackageName());
 
         uiAutomation.adoptShellPermissionIdentity(MANAGE_HEALTH_DATA);
         List<String> priorityList =
                 fetchDataOriginsPriorityOrder(HealthDataCategory.ACTIVITY)
                         .getDataOriginsPriorityOrder()
                         .stream()
-                        .map(dataOrigin -> dataOrigin.getPackageName())
-                        .collect(Collectors.toList());
+                        .map(DataOrigin::getPackageName)
+                        .toList();
 
         assertThat(
                         priorityList.equals(
                                 dataOriginPrioOrder.stream()
-                                        .map(dataOrigin -> dataOrigin.getPackageName())
-                                        .collect(Collectors.toList())))
+                                        .map(DataOrigin::getPackageName)
+                                        .toList()))
                 .isTrue();
 
-        Bundle bundle =
-                insertExerciseSessionAs(
-                        APP_A_WITH_READ_WRITE_PERMS,
-                        "01:00 PM",
-                        "03:00 PM",
-                        "02:00 PM",
-                        "03:00 PM");
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
-        bundle =
-                insertExerciseSessionAs(
-                        APP_B_WITH_READ_WRITE_PERMS, "02:00 PM", "03:00 PM", null, null);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        ExerciseSessionRecord sessionRecordA =
+                new ExerciseSessionRecord.Builder(
+                                getEmptyMetadata(),
+                                yesterdayAt("13:00"),
+                                yesterdayAt("15:00"),
+                                EXERCISE_SESSION_TYPE_RUNNING)
+                        .setSegments(
+                                List.of(
+                                        new ExerciseSegment.Builder(
+                                                        yesterdayAt("14:00"),
+                                                        yesterdayAt("15:00"),
+                                                        EXERCISE_SEGMENT_TYPE_PAUSE)
+                                                .build()))
+                        .build();
+        APP_A_WITH_READ_WRITE_PERMS.insertRecords(sessionRecordA);
+
+        ExerciseSessionRecord sessionRecordB =
+                new ExerciseSessionRecord.Builder(
+                                getEmptyMetadata(),
+                                yesterdayAt("14:00"),
+                                yesterdayAt("15:00"),
+                                EXERCISE_SESSION_TYPE_RUNNING)
+                        .build();
+        APP_B_WITH_READ_WRITE_PERMS.insertRecords(sessionRecordB);
 
         AggregateRecordsRequest<Long> aggregateRecordsRequest =
                 new AggregateRecordsRequest.Builder<Long>(
                                 new TimeInstantRangeFilter.Builder()
-                                        .setStartTime(getInstantTime("01:00 PM"))
-                                        .setEndTime(getInstantTime("03:00 PM"))
+                                        .setStartTime(yesterdayAt("13:00"))
+                                        .setEndTime(yesterdayAt("15:00"))
                                         .build())
                         .addAggregationType(EXERCISE_DURATION_TOTAL)
                         .build();
@@ -1044,14 +945,14 @@
         assertThat(response.get(EXERCISE_DURATION_TOTAL)).isNotNull();
         assertThat(response.get(EXERCISE_DURATION_TOTAL))
                 .isEqualTo(
-                        (getInstantTime("03:00 PM").toEpochMilli()
-                                        - getInstantTime("01:00 PM").toEpochMilli())
-                                - (getInstantTime("03:00 PM").toEpochMilli()
-                                        - getInstantTime("02:00 PM").toEpochMilli()));
+                        Duration.between(yesterdayAt("13:00"), yesterdayAt("15:00"))
+                                .minus(Duration.between(yesterdayAt("14:00"), yesterdayAt("15:00")))
+                                .toMillis());
 
         dataOriginPrioOrder =
-                getDataOriginPriorityOrder(
-                        APP_B_WITH_READ_WRITE_PERMS, APP_A_WITH_READ_WRITE_PERMS);
+                getDataOrigins(
+                        APP_B_WITH_READ_WRITE_PERMS.getPackageName(),
+                        APP_A_WITH_READ_WRITE_PERMS.getPackageName());
 
         uiAutomation.adoptShellPermissionIdentity(MANAGE_HEALTH_DATA);
         updateDataOriginPriorityOrder(
@@ -1063,22 +964,20 @@
                 fetchDataOriginsPriorityOrder(HealthDataCategory.ACTIVITY)
                         .getDataOriginsPriorityOrder()
                         .stream()
-                        .map(dataOrigin -> dataOrigin.getPackageName())
-                        .collect(Collectors.toList());
+                        .map(DataOrigin::getPackageName)
+                        .toList();
 
         assertThat(
                         priorityList.equals(
                                 dataOriginPrioOrder.stream()
-                                        .map(dataOrigin -> dataOrigin.getPackageName())
-                                        .collect(Collectors.toList())))
+                                        .map(DataOrigin::getPackageName)
+                                        .toList()))
                 .isTrue();
 
         AggregateRecordsResponse<Long> newResponse = getAggregateResponse(aggregateRecordsRequest);
         assertThat(newResponse.get(EXERCISE_DURATION_TOTAL)).isNotNull();
         assertThat(newResponse.get(EXERCISE_DURATION_TOTAL))
-                .isEqualTo(
-                        getInstantTime("03:00 PM").toEpochMilli()
-                                - getInstantTime("01:00 PM").toEpochMilli());
+                .isEqualTo(Duration.between(yesterdayAt("13:00"), yesterdayAt("15:00")).toMillis());
     }
 
     @Test
@@ -1087,41 +986,45 @@
         recordClassesToRead.add(HeartRateRecord.class.getName());
         recordClassesToRead.add(StepsRecord.class.getName());
 
-        Bundle bundle =
-                getChangeLogTokenAs(
-                        APP_B_WITH_READ_WRITE_PERMS,
-                        APP_A_WITH_READ_WRITE_PERMS.getPackageName(),
-                        recordClassesToRead);
-        String changeLogTokenForAppB = bundle.getString(CHANGE_LOG_TOKEN);
+        String changeLogTokenForAppB =
+                APP_B_WITH_READ_WRITE_PERMS.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addDataOriginFilter(
+                                        getDataOrigin(APP_A_WITH_READ_WRITE_PERMS.getPackageName()))
+                                .addRecordType(HeartRateRecord.class)
+                                .addRecordType(StepsRecord.class)
+                                .build());
 
-        bundle = insertRecordAs(APP_A_WITH_READ_WRITE_PERMS);
-        assertThat(bundle.getBoolean(SUCCESS)).isTrue();
+        APP_A_WITH_READ_WRITE_PERMS.insertRecords(TEST_RECORDS);
 
         List<String> healthPerms =
                 getGrantedHealthPermissions(APP_B_WITH_READ_WRITE_PERMS.getPackageName());
 
         revokeHealthPermissions(APP_B_WITH_READ_WRITE_PERMS.getPackageName());
 
-        try {
-            readChangeLogsUsingDataOriginFiltersAs(
-                    APP_B_WITH_READ_WRITE_PERMS, changeLogTokenForAppB);
-            Assert.fail(
-                    "Should have thrown exception in reading changeLogs without read permissions!");
-        } catch (HealthConnectException e) {
-            assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
-        }
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () ->
+                                APP_B_WITH_READ_WRITE_PERMS.getChangeLogs(
+                                        new ChangeLogsRequest.Builder(changeLogTokenForAppB)
+                                                .build()));
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
 
-        try {
-            getChangeLogTokenAs(
-                    APP_B_WITH_READ_WRITE_PERMS,
-                    APP_A_WITH_READ_WRITE_PERMS.getPackageName(),
-                    recordClassesToRead);
-            Assert.fail(
-                    "Should have thrown exception in getting change log token without read "
-                            + "permission!");
-        } catch (HealthConnectException e) {
-            assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
-        }
+        e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () ->
+                                APP_B_WITH_READ_WRITE_PERMS.getChangeLogToken(
+                                        new ChangeLogTokenRequest.Builder()
+                                                .addRecordType(HeartRateRecord.class)
+                                                .addRecordType(StepsRecord.class)
+                                                .addDataOriginFilter(
+                                                        getDataOrigin(
+                                                                APP_A_WITH_READ_WRITE_PERMS
+                                                                        .getPackageName()))
+                                                .build()));
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
 
         for (String perm : healthPerms) {
             grantPermission(APP_B_WITH_READ_WRITE_PERMS.getPackageName(), perm);
@@ -1131,17 +1034,42 @@
     private static StepsRecord getStepsRecord(
             int stepCount, Instant startTime, int durationInHours, String clientId) {
         return new StepsRecord.Builder(
-                        new Metadata.Builder()
-                                .setDataOrigin(
-                                        new DataOrigin.Builder()
-                                                .setPackageName(
-                                                        APP_WITH_WRITE_PERMS_ONLY.getPackageName())
-                                                .build())
-                                .setClientRecordId(clientId)
-                                .build(),
+                        getMetadataForClientId(
+                                clientId,
+                                getDataOrigin(APP_WITH_WRITE_PERMS_ONLY.getPackageName())),
                         startTime,
                         startTime.plus(durationInHours, ChronoUnit.HOURS),
                         stepCount)
                 .build();
     }
+
+    private static StepsRecord getStepsRecord(Metadata metadata) {
+        Instant startTime = NOW.minus(ofMinutes(10));
+        Instant endTime = NOW.minus(ofMinutes(5));
+        return new StepsRecord.Builder(metadata, startTime, endTime, 155).build();
+    }
+
+    private static HeartRateRecord getHeartRateRecord(Metadata metadata) {
+        Instant startTime = NOW.minus(ofMinutes(10));
+        Instant endTime = NOW.minus(ofMinutes(5));
+        return new HeartRateRecord.Builder(
+                        metadata,
+                        startTime,
+                        endTime,
+                        List.of(new HeartRateRecord.HeartRateSample(75, startTime.plusSeconds(5))))
+                .build();
+    }
+
+    private static BasalMetabolicRateRecord getBasalMetabolicRateRecord(Metadata metadata) {
+        Instant time = NOW.minus(ofMinutes(10));
+        return new BasalMetabolicRateRecord.Builder(metadata, time, Power.fromWatts(10)).build();
+    }
+
+    private static ExerciseSessionRecord getExerciseSessionRecord(Metadata metadata) {
+        Instant startTime = NOW.minus(ofMinutes(10));
+        Instant endTime = NOW.minus(ofMinutes(5));
+        return new ExerciseSessionRecord.Builder(
+                        metadata, startTime, endTime, EXERCISE_SESSION_TYPE_RUNNING)
+                .build();
+    }
 }
diff --git a/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/dailyjob/DailyDeleteAccessLogTest.java b/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/dailyjob/DailyDeleteAccessLogTest.java
index 7d29f05..d5188c7 100644
--- a/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/dailyjob/DailyDeleteAccessLogTest.java
+++ b/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/dailyjob/DailyDeleteAccessLogTest.java
@@ -51,6 +51,9 @@
 
     @Override
     protected void tearDown() throws Exception {
+        if (!isHardwareSupported(getDevice())) {
+            return;
+        }
         clearData(getDevice());
         resetTime(getDevice(), mTestStartTime, mDeviceStartTime);
         super.tearDown();
diff --git a/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/logging/HealthConnectDailyLogsStatsTests.java b/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/logging/HealthConnectDailyLogsStatsTests.java
index eb2a5e7..6d5906f 100644
--- a/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/logging/HealthConnectDailyLogsStatsTests.java
+++ b/tests/cts/hostsidetests/healthconnect/host/src/android/healthconnect/cts/logging/HealthConnectDailyLogsStatsTests.java
@@ -77,6 +77,9 @@
 
     @Override
     protected void tearDown() throws Exception {
+        if (!isHardwareSupported(getDevice())) {
+            return;
+        }
         // TODO(b/313055175): Do not disable rate limiting once b/300238889 is resolved.
         HostSideTestUtil.restoreRateLimitingFeatureFlag(getDevice());
         ConfigUtils.removeConfig(getDevice());
diff --git a/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/BundleHelper.java b/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/BundleHelper.java
new file mode 100644
index 0000000..4129e2a
--- /dev/null
+++ b/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/BundleHelper.java
@@ -0,0 +1,668 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts.lib;
+
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.ReadRecordsRequestUsingIds;
+import android.health.connect.RecordIdFilter;
+import android.health.connect.TimeInstantRangeFilter;
+import android.health.connect.changelog.ChangeLogTokenRequest;
+import android.health.connect.changelog.ChangeLogsRequest;
+import android.health.connect.changelog.ChangeLogsResponse;
+import android.health.connect.datatypes.BasalMetabolicRateRecord;
+import android.health.connect.datatypes.DataOrigin;
+import android.health.connect.datatypes.ExerciseRoute;
+import android.health.connect.datatypes.ExerciseSegment;
+import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.health.connect.datatypes.HeartRateRecord;
+import android.health.connect.datatypes.InstantRecord;
+import android.health.connect.datatypes.IntervalRecord;
+import android.health.connect.datatypes.Metadata;
+import android.health.connect.datatypes.Record;
+import android.health.connect.datatypes.StepsRecord;
+import android.health.connect.datatypes.units.Length;
+import android.health.connect.datatypes.units.Power;
+import android.os.Bundle;
+
+import java.lang.reflect.InvocationTargetException;
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.IntStream;
+
+/** Converters from/to bundles for HC request, response, and record types. */
+public final class BundleHelper {
+    private static final String PREFIX = "android.healthconnect.cts.";
+    public static final String QUERY_TYPE = PREFIX + "QUERY_TYPE";
+    public static final String INSERT_RECORDS_QUERY = PREFIX + "INSERT_RECORDS_QUERY";
+    public static final String READ_RECORDS_QUERY = PREFIX + "READ_RECORDS_QUERY";
+    public static final String READ_RECORDS_USING_IDS_QUERY =
+            PREFIX + "READ_RECORDS_USING_IDS_QUERY";
+    public static final String READ_CHANGE_LOGS_QUERY = PREFIX + "READ_CHANGE_LOGS_QUERY";
+    public static final String DELETE_RECORDS_QUERY = PREFIX + "DELETE_RECORDS_QUERY";
+    public static final String UPDATE_RECORDS_QUERY = PREFIX + "UPDATE_RECORDS_QUERY";
+    public static final String GET_CHANGE_LOG_TOKEN_QUERY = PREFIX + "GET_CHANGE_LOG_TOKEN_QUERY";
+    public static final String INTENT_EXCEPTION = PREFIX + "INTENT_EXCEPTION";
+
+    private static final String CHANGE_LOGS_RESPONSE = PREFIX + "CHANGE_LOGS_RESPONSE";
+    private static final String CHANGE_LOG_TOKEN = PREFIX + "CHANGE_LOG_TOKEN";
+    private static final String RECORD_CLASS_NAME = PREFIX + "RECORD_CLASS_NAME";
+    private static final String START_TIME_MILLIS = PREFIX + "START_TIME_MILLIS";
+    private static final String END_TIME_MILLIS = PREFIX + "END_TIME_MILLIS";
+    private static final String EXERCISE_SESSION_TYPE = PREFIX + "EXERCISE_SESSION_TYPE";
+    private static final String RECORD_LIST = PREFIX + "RECORD_LIST";
+    private static final String PACKAGE_NAME = PREFIX + "PACKAGE_NAME";
+    private static final String CLIENT_ID = PREFIX + "CLIENT_ID";
+    private static final String RECORD_ID = PREFIX + "RECORD_ID";
+    private static final String METADATA = PREFIX + "METADATA";
+    private static final String VALUES = PREFIX + "VALUES";
+    private static final String COUNT = PREFIX + "COUNT";
+    private static final String SAMPLE_TIMES = PREFIX + "SAMPLE_TIMES";
+    private static final String SAMPLE_VALUES = PREFIX + "SAMPLE_VALUES";
+    private static final String EXERCISE_ROUTE_TIMESTAMPS = PREFIX + "EXERCISE_ROUTE_TIMESTAMPS";
+    private static final String EXERCISE_ROUTE_LATITUDES = PREFIX + "EXERCISE_ROUTE_LATITUDES";
+    private static final String EXERCISE_ROUTE_LONGITUDES = PREFIX + "EXERCISE_ROUTE_LONGITUDES";
+    private static final String EXERCISE_ROUTE_ALTITUDES = PREFIX + "EXERCISE_ROUTE_ALTITUDES";
+    private static final String EXERCISE_ROUTE_HACCS = PREFIX + "EXERCISE_ROUTE_HACCS";
+    private static final String EXERCISE_ROUTE_VACCS = PREFIX + "EXERCISE_ROUTE_VACCS";
+    private static final String EXERCISE_HAS_ROUTE = PREFIX + "EXERCISE_HAS_ROUTE";
+    private static final String POWER_WATTS = PREFIX + "POWER_WATTS";
+    private static final String TIME_INSTANT_RANGE_FILTER = PREFIX + "TIME_INSTANT_RANGE_FILTER";
+    private static final String CHANGE_LOGS_REQUEST = PREFIX + "CHANGE_LOGS_REQUEST";
+    private static final String CHANGE_LOG_TOKEN_REQUEST = PREFIX + "CHANGE_LOG_TOKEN_REQUEST";
+    private static final String EXERCISE_SEGMENT_START_TIMES =
+            PREFIX + "EXERCISE_SEGMENT_START_TIMES";
+    private static final String EXERCISE_SEGMENT_END_TIMES = PREFIX + "EXERCISE_SEGMENT_END_TIMES";
+    private static final String EXERCISE_SEGMENT_TYPES = PREFIX + "EXERCISE_SEGMENT_TYPES";
+
+    /** Converts an insert records request to a bundle. */
+    public static Bundle fromInsertRecordsRequest(List<Record> records) {
+        Bundle bundle = new Bundle();
+        bundle.putString(QUERY_TYPE, INSERT_RECORDS_QUERY);
+        bundle.putParcelableArrayList(RECORD_LIST, new ArrayList<>(fromRecordList(records)));
+        return bundle;
+    }
+
+    /** Converts a bundle to an insert records request. */
+    public static List<? extends Record> toInsertRecordsRequest(Bundle bundle) {
+        return toRecordList(bundle.getParcelableArrayList(RECORD_LIST, Bundle.class));
+    }
+
+    /** Converts an update records request to a bundle. */
+    public static Bundle fromUpdateRecordsRequest(List<Record> records) {
+        Bundle bundle = new Bundle();
+        bundle.putString(QUERY_TYPE, UPDATE_RECORDS_QUERY);
+        bundle.putParcelableArrayList(RECORD_LIST, new ArrayList<>(fromRecordList(records)));
+        return bundle;
+    }
+
+    /** Converts a bundle to an update records request. */
+    public static List<? extends Record> toUpdateRecordsRequest(Bundle bundle) {
+        return toRecordList(bundle.getParcelableArrayList(RECORD_LIST, Bundle.class));
+    }
+
+    /** Converts an insert records response to a bundle. */
+    public static Bundle fromInsertRecordsResponse(List<String> recordIds) {
+        Bundle bundle = new Bundle();
+        bundle.putStringArrayList(RECORD_ID, new ArrayList<>(recordIds));
+        return bundle;
+    }
+
+    /** Converts a bundle to an insert records response. */
+    public static List<String> toInsertRecordsResponse(Bundle bundle) {
+        return bundle.getStringArrayList(RECORD_ID);
+    }
+
+    /** Converts a ReadRecordsRequestUsingFilters to a bundle. */
+    public static <T extends Record> Bundle fromReadRecordsRequestUsingFilters(
+            ReadRecordsRequestUsingFilters<T> request) {
+        Bundle bundle = new Bundle();
+        bundle.putString(QUERY_TYPE, READ_RECORDS_QUERY);
+        bundle.putString(RECORD_CLASS_NAME, request.getRecordType().getName());
+        bundle.putStringArrayList(
+                PACKAGE_NAME,
+                new ArrayList<>(
+                        request.getDataOrigins().stream()
+                                .map(DataOrigin::getPackageName)
+                                .toList()));
+
+        if (request.getTimeRangeFilter() instanceof TimeInstantRangeFilter filter) {
+            bundle.putBoolean(TIME_INSTANT_RANGE_FILTER, true);
+
+            Long startTime = transformOrNull(filter.getStartTime(), Instant::toEpochMilli);
+            Long endTime = transformOrNull(filter.getEndTime(), Instant::toEpochMilli);
+
+            bundle.putSerializable(START_TIME_MILLIS, startTime);
+            bundle.putSerializable(END_TIME_MILLIS, endTime);
+        } else if (request.getTimeRangeFilter() != null) {
+            throw new IllegalArgumentException("Unsupported time range filter");
+        }
+
+        return bundle;
+    }
+
+    /** Converts a bundle to a ReadRecordsRequestUsingFilters. */
+    public static ReadRecordsRequestUsingFilters<? extends Record> toReadRecordsRequestUsingFilters(
+            Bundle bundle) {
+        String recordClassName = bundle.getString(RECORD_CLASS_NAME);
+
+        Class<? extends Record> recordClass = recordClassForName(recordClassName);
+
+        ReadRecordsRequestUsingFilters.Builder<? extends Record> request =
+                new ReadRecordsRequestUsingFilters.Builder<>(recordClass);
+
+        if (bundle.getBoolean(TIME_INSTANT_RANGE_FILTER)) {
+            Long startTimeMillis = bundle.getSerializable(START_TIME_MILLIS, Long.class);
+            Long endTimeMillis = bundle.getSerializable(END_TIME_MILLIS, Long.class);
+
+            Instant startTime = transformOrNull(startTimeMillis, Instant::ofEpochMilli);
+            Instant endTime = transformOrNull(endTimeMillis, Instant::ofEpochMilli);
+
+            TimeInstantRangeFilter timeInstantRangeFilter =
+                    new TimeInstantRangeFilter.Builder()
+                            .setStartTime(startTime)
+                            .setEndTime(endTime)
+                            .build();
+
+            request.setTimeRangeFilter(timeInstantRangeFilter);
+        }
+        List<String> packageNames = bundle.getStringArrayList(PACKAGE_NAME);
+
+        if (packageNames != null) {
+            for (String packageName : packageNames) {
+                request.addDataOrigins(
+                        new DataOrigin.Builder().setPackageName(packageName).build());
+            }
+        }
+
+        return request.build();
+    }
+
+    /** Converts a ReadRecordsRequestUsingFilters to a bundle. */
+    public static <T extends Record> Bundle fromReadRecordsRequestUsingIds(
+            ReadRecordsRequestUsingIds<T> request) {
+        Bundle bundle = new Bundle();
+        bundle.putString(QUERY_TYPE, READ_RECORDS_USING_IDS_QUERY);
+        bundle.putString(RECORD_CLASS_NAME, request.getRecordType().getName());
+
+        var recordIdFilters = request.getRecordIdFilters();
+        List<String> recordIds = recordIdFilters.stream().map(RecordIdFilter::getId).toList();
+        bundle.putStringArrayList(RECORD_ID, new ArrayList<>(recordIds));
+
+        return bundle;
+    }
+
+    /** Converts a bundle to a ReadRecordsRequestUsingFilters. */
+    public static ReadRecordsRequestUsingIds<? extends Record> toReadRecordsRequestUsingIds(
+            Bundle bundle) {
+        String recordClassName = bundle.getString(RECORD_CLASS_NAME);
+        var request = new ReadRecordsRequestUsingIds.Builder<>(recordClassForName(recordClassName));
+        var recordIds = bundle.getStringArrayList(RECORD_ID);
+        for (String id : recordIds) {
+            request.addId(id);
+        }
+
+        return request.build();
+    }
+
+    /** Converts a read records response to a bundle. */
+    public static Bundle fromReadRecordsResponse(List<? extends Record> records) {
+        Bundle bundle = new Bundle();
+        bundle.putParcelableArrayList(RECORD_LIST, new ArrayList<>(fromRecordList(records)));
+        return bundle;
+    }
+
+    /** Converts a bundle to a read records response. */
+    public static <T extends Record> List<T> toReadRecordsResponse(Bundle bundle) {
+        return (List<T>) toRecordList(bundle.getParcelableArrayList(RECORD_LIST, Bundle.class));
+    }
+
+    /** Converts a delete records request to a bundle. */
+    public static Bundle fromDeleteRecordsByIdsRequest(List<RecordIdFilter> recordIdFilters) {
+        Bundle bundle = new Bundle();
+        bundle.putString(QUERY_TYPE, DELETE_RECORDS_QUERY);
+
+        List<String> recordClassNames =
+                recordIdFilters.stream()
+                        .map(RecordIdFilter::getRecordType)
+                        .map(Class::getName)
+                        .toList();
+        List<String> recordIds = recordIdFilters.stream().map(RecordIdFilter::getId).toList();
+
+        bundle.putStringArrayList(RECORD_CLASS_NAME, new ArrayList<>(recordClassNames));
+        bundle.putStringArrayList(RECORD_ID, new ArrayList<>(recordIds));
+
+        return bundle;
+    }
+
+    /** Converts a bundle to a delete records request. */
+    public static List<RecordIdFilter> toDeleteRecordsByIdsRequest(Bundle bundle) {
+        List<String> recordClassNames = bundle.getStringArrayList(RECORD_CLASS_NAME);
+        List<String> recordIds = bundle.getStringArrayList(RECORD_ID);
+
+        return IntStream.range(0, recordClassNames.size())
+                .mapToObj(
+                        i -> {
+                            String recordClassName = recordClassNames.get(i);
+                            Class<? extends Record> recordClass =
+                                    recordClassForName(recordClassName);
+                            String recordId = recordIds.get(i);
+                            return RecordIdFilter.fromId(recordClass, recordId);
+                        })
+                .toList();
+    }
+
+    /** Converts a ChangeLogTokenRequest to a bundle. */
+    public static Bundle fromChangeLogTokenRequest(ChangeLogTokenRequest request) {
+        Bundle bundle = new Bundle();
+        bundle.putString(QUERY_TYPE, GET_CHANGE_LOG_TOKEN_QUERY);
+        bundle.putParcelable(CHANGE_LOG_TOKEN_REQUEST, request);
+        return bundle;
+    }
+
+    /** Converts a bundle to a ChangeLogTokenRequest. */
+    public static ChangeLogTokenRequest toChangeLogTokenRequest(Bundle bundle) {
+        return bundle.getParcelable(CHANGE_LOG_TOKEN_REQUEST, ChangeLogTokenRequest.class);
+    }
+
+    /** Converts a changelog token response to a bundle. */
+    public static Bundle fromChangeLogTokenResponse(String token) {
+        Bundle bundle = new Bundle();
+        bundle.putString(CHANGE_LOG_TOKEN, token);
+        return bundle;
+    }
+
+    /** Converts a bundle to a change log token response. */
+    public static String toChangeLogTokenResponse(Bundle bundle) {
+        return bundle.getString(CHANGE_LOG_TOKEN);
+    }
+
+    /** Converts a ChangeLogsRequest to a bundle. */
+    public static Bundle fromChangeLogsRequest(ChangeLogsRequest request) {
+        Bundle bundle = new Bundle();
+        bundle.putString(QUERY_TYPE, READ_CHANGE_LOGS_QUERY);
+        bundle.putParcelable(CHANGE_LOGS_REQUEST, request);
+        return bundle;
+    }
+
+    /** Converts a bundle to a ChangeLogsRequest. */
+    public static ChangeLogsRequest toChangeLogsRequest(Bundle bundle) {
+        return bundle.getParcelable(CHANGE_LOGS_REQUEST, ChangeLogsRequest.class);
+    }
+
+    /** Converts a ChangeLogsResponse to a bundle. */
+    public static Bundle fromChangeLogsResponse(ChangeLogsResponse response) {
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(CHANGE_LOGS_RESPONSE, response);
+        return bundle;
+    }
+
+    /** Converts a bundle to a ChangeLogsResponse. */
+    public static ChangeLogsResponse toChangeLogsResponse(Bundle bundle) {
+        return bundle.getParcelable(CHANGE_LOGS_RESPONSE, ChangeLogsResponse.class);
+    }
+
+    private static List<Bundle> fromRecordList(List<? extends Record> records) {
+        return records.stream().map(BundleHelper::fromRecord).toList();
+    }
+
+    private static List<? extends Record> toRecordList(List<Bundle> bundles) {
+        return bundles.stream().map(BundleHelper::toRecord).toList();
+    }
+
+    private static Bundle fromRecord(Record record) {
+        Bundle bundle = new Bundle();
+        bundle.putString(RECORD_CLASS_NAME, record.getClass().getName());
+        bundle.putBundle(METADATA, fromMetadata(record.getMetadata()));
+
+        if (record instanceof IntervalRecord intervalRecord) {
+            bundle.putLong(START_TIME_MILLIS, intervalRecord.getStartTime().toEpochMilli());
+            bundle.putLong(END_TIME_MILLIS, intervalRecord.getEndTime().toEpochMilli());
+        } else if (record instanceof InstantRecord instantRecord) {
+            bundle.putLong(START_TIME_MILLIS, instantRecord.getTime().toEpochMilli());
+        } else {
+            throw new IllegalArgumentException("Unsupported record type: ");
+        }
+
+        Bundle values;
+
+        if (record instanceof BasalMetabolicRateRecord basalMetabolicRateRecord) {
+            values = getBasalMetabolicRateRecordValues(basalMetabolicRateRecord);
+        } else if (record instanceof ExerciseSessionRecord exerciseSessionRecord) {
+            values = getExerciseSessionRecordValues(exerciseSessionRecord);
+        } else if (record instanceof StepsRecord stepsRecord) {
+            values = getStepsRecordValues(stepsRecord);
+        } else if (record instanceof HeartRateRecord heartRateRecord) {
+            values = getHeartRateRecordValues(heartRateRecord);
+        } else {
+            throw new IllegalArgumentException(
+                    "Unsupported record type: " + record.getClass().getName());
+        }
+
+        bundle.putBundle(VALUES, values);
+
+        Record decodedRecord = toRecord(bundle);
+        if (!record.equals(decodedRecord)) {
+            throw new IllegalArgumentException(
+                    "Some fields are incorrectly encoded in " + record.getClass().getSimpleName());
+        }
+
+        return bundle;
+    }
+
+    private static Record toRecord(Bundle bundle) {
+        Metadata metadata = toMetadata(bundle.getBundle(METADATA));
+
+        String recordClassName = bundle.getString(RECORD_CLASS_NAME);
+
+        Instant startTime = Instant.ofEpochMilli(bundle.getLong(START_TIME_MILLIS));
+        Instant endTime = Instant.ofEpochMilli(bundle.getLong(END_TIME_MILLIS));
+
+        Bundle values = bundle.getBundle(VALUES);
+
+        if (Objects.equals(recordClassName, BasalMetabolicRateRecord.class.getName())) {
+            return createBasalMetabolicRateRecord(metadata, startTime, values);
+        } else if (Objects.equals(recordClassName, ExerciseSessionRecord.class.getName())) {
+            return createExerciseSessionRecord(metadata, startTime, endTime, values);
+        } else if (Objects.equals(recordClassName, HeartRateRecord.class.getName())) {
+            return createHeartRateRecord(metadata, startTime, endTime, values);
+        } else if (Objects.equals(recordClassName, StepsRecord.class.getName())) {
+            return createStepsRecord(metadata, startTime, endTime, values);
+        }
+
+        throw new IllegalArgumentException("Unsupported record type: " + recordClassName);
+    }
+
+    private static Bundle getBasalMetabolicRateRecordValues(BasalMetabolicRateRecord record) {
+        Bundle values = new Bundle();
+        values.putDouble(POWER_WATTS, record.getBasalMetabolicRate().getInWatts());
+        return values;
+    }
+
+    private static BasalMetabolicRateRecord createBasalMetabolicRateRecord(
+            Metadata metadata, Instant time, Bundle values) {
+        double powerWatts = values.getDouble(POWER_WATTS);
+
+        return new BasalMetabolicRateRecord.Builder(metadata, time, Power.fromWatts(powerWatts))
+                .build();
+    }
+
+    private static Bundle getExerciseSessionRecordValues(ExerciseSessionRecord record) {
+        Bundle values = new Bundle();
+
+        values.putInt(EXERCISE_SESSION_TYPE, record.getExerciseType());
+
+        ExerciseRoute route = record.getRoute();
+
+        if (route != null) {
+            long[] timestamps =
+                    route.getRouteLocations().stream()
+                            .map(ExerciseRoute.Location::getTime)
+                            .mapToLong(Instant::toEpochMilli)
+                            .toArray();
+            double[] latitudes =
+                    route.getRouteLocations().stream()
+                            .mapToDouble(ExerciseRoute.Location::getLatitude)
+                            .toArray();
+            double[] longitudes =
+                    route.getRouteLocations().stream()
+                            .mapToDouble(ExerciseRoute.Location::getLongitude)
+                            .toArray();
+            List<Double> altitudes =
+                    route.getRouteLocations().stream()
+                            .map(ExerciseRoute.Location::getAltitude)
+                            .map(alt -> transformOrNull(alt, Length::getInMeters))
+                            .toList();
+            List<Double> hAccs =
+                    route.getRouteLocations().stream()
+                            .map(ExerciseRoute.Location::getHorizontalAccuracy)
+                            .map(hAcc -> transformOrNull(hAcc, Length::getInMeters))
+                            .toList();
+            List<Double> vAccs =
+                    route.getRouteLocations().stream()
+                            .map(ExerciseRoute.Location::getVerticalAccuracy)
+                            .map(vAcc -> transformOrNull(vAcc, Length::getInMeters))
+                            .toList();
+
+            values.putLongArray(EXERCISE_ROUTE_TIMESTAMPS, timestamps);
+            values.putDoubleArray(EXERCISE_ROUTE_LATITUDES, latitudes);
+            values.putDoubleArray(EXERCISE_ROUTE_LONGITUDES, longitudes);
+            values.putSerializable(EXERCISE_ROUTE_ALTITUDES, new ArrayList<>(altitudes));
+            values.putSerializable(EXERCISE_ROUTE_HACCS, new ArrayList<>(hAccs));
+            values.putSerializable(EXERCISE_ROUTE_VACCS, new ArrayList<>(vAccs));
+        }
+
+        values.putBoolean(EXERCISE_HAS_ROUTE, record.hasRoute());
+
+        long[] segmentStartTimes =
+                record.getSegments().stream()
+                        .map(ExerciseSegment::getStartTime)
+                        .mapToLong(Instant::toEpochMilli)
+                        .toArray();
+        long[] segmentEndTimes =
+                record.getSegments().stream()
+                        .map(ExerciseSegment::getEndTime)
+                        .mapToLong(Instant::toEpochMilli)
+                        .toArray();
+        int[] segmentTypes =
+                record.getSegments().stream().mapToInt(ExerciseSegment::getSegmentType).toArray();
+
+        values.putLongArray(EXERCISE_SEGMENT_START_TIMES, segmentStartTimes);
+        values.putLongArray(EXERCISE_SEGMENT_END_TIMES, segmentEndTimes);
+        values.putIntArray(EXERCISE_SEGMENT_TYPES, segmentTypes);
+
+        return values;
+    }
+
+    private static ExerciseSessionRecord createExerciseSessionRecord(
+            Metadata metadata, Instant startTime, Instant endTime, Bundle values) {
+        int exerciseType = values.getInt(EXERCISE_SESSION_TYPE);
+
+        ExerciseSessionRecord.Builder record =
+                new ExerciseSessionRecord.Builder(metadata, startTime, endTime, exerciseType);
+
+        long[] routeTimestamps = values.getLongArray(EXERCISE_ROUTE_TIMESTAMPS);
+
+        int locationCount = routeTimestamps == null ? 0 : routeTimestamps.length;
+
+        if (locationCount > 0) {
+            double[] latitudes = values.getDoubleArray(EXERCISE_ROUTE_LATITUDES);
+            double[] longitudes = values.getDoubleArray(EXERCISE_ROUTE_LONGITUDES);
+            List<Double> altitudes =
+                    values.getSerializable(EXERCISE_ROUTE_ALTITUDES, ArrayList.class);
+            List<Double> hAccs = values.getSerializable(EXERCISE_ROUTE_HACCS, ArrayList.class);
+            List<Double> vAccs = values.getSerializable(EXERCISE_ROUTE_VACCS, ArrayList.class);
+            List<ExerciseRoute.Location> locations =
+                    IntStream.range(0, locationCount)
+                            .mapToObj(
+                                    i -> {
+                                        Instant time = Instant.ofEpochMilli(routeTimestamps[i]);
+                                        double latitude = latitudes[i];
+                                        double longitude = longitudes[i];
+                                        Double altitude = altitudes.get(i);
+                                        Double hAcc = hAccs.get(i);
+                                        Double vAcc = vAccs.get(i);
+
+                                        var location =
+                                                new ExerciseRoute.Location.Builder(
+                                                        time, latitude, longitude);
+
+                                        if (altitude != null) {
+                                            location.setAltitude(Length.fromMeters(altitude));
+                                        }
+
+                                        if (hAcc != null) {
+                                            location.setHorizontalAccuracy(Length.fromMeters(hAcc));
+                                        }
+
+                                        if (vAcc != null) {
+                                            location.setVerticalAccuracy(Length.fromMeters(vAcc));
+                                        }
+
+                                        return location.build();
+                                    })
+                            .toList();
+
+            record.setRoute(new ExerciseRoute(locations));
+        }
+
+        boolean hasRoute = values.getBoolean(EXERCISE_HAS_ROUTE);
+
+        if (hasRoute && locationCount == 0) {
+            // Handle the `route == null && hasRoute == true` case which is a valid state.
+            setHasRoute(record, hasRoute);
+        }
+
+        long[] segmentStartTimes = values.getLongArray(EXERCISE_SEGMENT_START_TIMES);
+        long[] segmentEndTimes = values.getLongArray(EXERCISE_SEGMENT_END_TIMES);
+        int[] segmentTypes = values.getIntArray(EXERCISE_SEGMENT_TYPES);
+
+        List<ExerciseSegment> segments =
+                IntStream.range(0, segmentStartTimes.length)
+                        .mapToObj(
+                                i -> {
+                                    Instant segmentStartTime =
+                                            Instant.ofEpochMilli(segmentStartTimes[i]);
+                                    Instant segmentEndTime =
+                                            Instant.ofEpochMilli(segmentEndTimes[i]);
+                                    return new ExerciseSegment.Builder(
+                                                    segmentStartTime,
+                                                    segmentEndTime,
+                                                    segmentTypes[i])
+                                            .build();
+                                })
+                        .toList();
+
+        record.setSegments(segments);
+
+        return record.build();
+    }
+
+    private static Bundle getHeartRateRecordValues(HeartRateRecord record) {
+        Bundle values = new Bundle();
+        long[] times =
+                record.getSamples().stream()
+                        .map(HeartRateRecord.HeartRateSample::getTime)
+                        .mapToLong(Instant::toEpochMilli)
+                        .toArray();
+        long[] bpms =
+                record.getSamples().stream()
+                        .mapToLong(HeartRateRecord.HeartRateSample::getBeatsPerMinute)
+                        .toArray();
+
+        values.putLongArray(SAMPLE_TIMES, times);
+        values.putLongArray(SAMPLE_VALUES, bpms);
+        return values;
+    }
+
+    private static HeartRateRecord createHeartRateRecord(
+            Metadata metadata, Instant startTime, Instant endTime, Bundle values) {
+
+        long[] times = values.getLongArray(SAMPLE_TIMES);
+        long[] bpms = values.getLongArray(SAMPLE_VALUES);
+
+        List<HeartRateRecord.HeartRateSample> samples =
+                IntStream.range(0, times.length)
+                        .mapToObj(
+                                i ->
+                                        new HeartRateRecord.HeartRateSample(
+                                                bpms[i], Instant.ofEpochMilli(times[i])))
+                        .toList();
+
+        return new HeartRateRecord.Builder(metadata, startTime, endTime, samples).build();
+    }
+
+    private static Bundle getStepsRecordValues(StepsRecord record) {
+        Bundle values = new Bundle();
+        values.putLong(COUNT, record.getCount());
+        return values;
+    }
+
+    private static StepsRecord createStepsRecord(
+            Metadata metadata, Instant startTime, Instant endTime, Bundle values) {
+        long count = values.getLong(COUNT);
+
+        return new StepsRecord.Builder(metadata, startTime, endTime, count).build();
+    }
+
+    private static Bundle fromMetadata(Metadata metadata) {
+        Bundle bundle = new Bundle();
+        bundle.putString(RECORD_ID, metadata.getId());
+        bundle.putString(PACKAGE_NAME, metadata.getDataOrigin().getPackageName());
+        bundle.putString(CLIENT_ID, metadata.getClientRecordId());
+        return bundle;
+    }
+
+    private static Metadata toMetadata(Bundle bundle) {
+        Metadata.Builder metadata = new Metadata.Builder();
+
+        ifNotNull(bundle.getString(RECORD_ID), metadata::setId);
+        ifNotNull(
+                bundle.getString(PACKAGE_NAME),
+                packageName ->
+                        metadata.setDataOrigin(
+                                new DataOrigin.Builder().setPackageName(packageName).build()));
+        metadata.setClientRecordId(bundle.getString(CLIENT_ID));
+
+        return metadata.build();
+    }
+
+    private static <T> void ifNotNull(T obj, Consumer<T> consumer) {
+        if (obj == null) {
+            return;
+        }
+        consumer.accept(obj);
+    }
+
+    private static <T, R> R transformOrNull(T obj, Function<T, R> transform) {
+        if (obj == null) {
+            return null;
+        }
+        return transform.apply(obj);
+    }
+
+    private static Class<? extends Record> recordClassForName(String className) {
+        try {
+            return (Class<? extends Record>) Class.forName(className);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    /**
+     * Calls {@code ExerciseSessionRecord.Builder.setHasRoute} using reflection as the method is
+     * hidden.
+     */
+    private static void setHasRoute(ExerciseSessionRecord.Builder record, boolean hasRoute) {
+        // Getting a hidden method by its signature using getMethod() throws an exception in test
+        // apps, but iterating throw all the methods and getting the needed one works.
+        for (var method : record.getClass().getMethods()) {
+            if (method.getName().equals("setHasRoute")) {
+                try {
+                    method.invoke(record, hasRoute);
+                } catch (IllegalAccessException | InvocationTargetException e) {
+                    throw new IllegalArgumentException(e);
+                }
+            }
+        }
+    }
+
+    private BundleHelper() {}
+}
diff --git a/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/MultiAppTestUtils.java b/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/MultiAppTestUtils.java
deleted file mode 100644
index 25976fd..0000000
--- a/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/MultiAppTestUtils.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2023 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 android.healthconnect.cts.lib;
-
-import android.health.connect.datatypes.DataOrigin;
-import android.healthconnect.cts.utils.TestUtils;
-import android.os.Bundle;
-
-import com.android.cts.install.lib.TestApp;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-
-public class MultiAppTestUtils {
-    public static final String QUERY_TYPE = "android.healthconnect.cts.queryType";
-    public static final String INTENT_EXTRA_CALLING_PKG = "android.healthconnect.cts.calling_pkg";
-    public static final String APP_PKG_NAME_USED_IN_DATA_ORIGIN =
-            "android.healthconnect.cts.pkg.usedInDataOrigin";
-    public static final String INSERT_RECORD_QUERY = "android.healthconnect.cts.insertRecord";
-    public static final String READ_RECORDS_QUERY = "android.healthconnect.cts.readRecords";
-    public static final String READ_RECORDS_SIZE = "android.healthconnect.cts.readRecordsNumber";
-    public static final String READ_USING_DATA_ORIGIN_FILTERS =
-            "android.healthconnect.cts.readUsingDataOriginFilters";
-
-    public static final String DATA_ORIGIN_FILTER_PACKAGE_NAMES =
-            "android.healthconnect.cts.dataOriginFilterPackageNames";
-    public static final String READ_RECORD_CLASS_NAME =
-            "android.healthconnect.cts.readRecordsClass";
-    public static final String READ_CHANGE_LOGS_QUERY = "android.healthconnect.cts.readChangeLogs";
-    public static final String CHANGE_LOGS_RESPONSE =
-            "android.healthconnect.cts.changeLogsResponse";
-    public static final String CHANGE_LOG_TOKEN = "android.healthconnect.cts.changeLogToken";
-    public static final String SUCCESS = "android.healthconnect.cts.success";
-    public static final String CLIENT_ID = "android.healthconnect.cts.clientId";
-    public static final String RECORD_IDS = "android.healthconnect.cts.records";
-    public static final String DELETE_RECORDS_QUERY = "android.healthconnect.cts.deleteRecords";
-    public static final String UPDATE_RECORDS_QUERY = "android.healthconnect.cts.updateRecords";
-    public static final String UPDATE_EXERCISE_ROUTE = "android.healthconnect.cts.updateRoute";
-
-    public static final String UPSERT_EXERCISE_ROUTE = "android.healthconnect.cts.upsertRoute";
-    public static final String GET_CHANGE_LOG_TOKEN_QUERY =
-            "android.healthconnect.cts.getChangeLogToken";
-    public static final String RECORD_TYPE = "android.healthconnect.cts.recordType";
-    public static final String STEPS_RECORD = "android.healthconnect.cts.stepsRecord";
-    public static final String EXERCISE_SESSION = "android.healthconnect.cts.exerciseSession";
-    public static final String START_TIME = "android.healthconnect.cts.startTime";
-    public static final String END_TIME = "android.healthconnect.cts.endTime";
-    public static final String STEPS_COUNT = "android.healthconnect.cts.stepsCount";
-    public static final String PAUSE_START = "android.healthconnect.cts.pauseStart";
-    public static final String PAUSE_END = "android.healthconnect.cts.pauseEnd";
-    public static final String INTENT_EXCEPTION = "android.healthconnect.cts.exception";
-
-    public static Bundle insertRecordAs(TestApp testApp) throws Exception {
-        return TestAppProxy.forApp(testApp).insertRecord();
-    }
-
-    public static Bundle deleteRecordsAs(
-            TestApp testApp, List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass)
-            throws Exception {
-        return TestAppProxy.forApp(testApp).deleteRecords(listOfRecordIdsAndClass);
-    }
-
-    public static Bundle updateRecordsAs(
-            TestApp testAppToUpdateData,
-            List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass)
-            throws Exception {
-        return TestAppProxy.forApp(testAppToUpdateData).updateRecords(listOfRecordIdsAndClass);
-    }
-
-    public static Bundle updateRouteAs(TestApp testAppToUpdateData) throws Exception {
-        return TestAppProxy.forApp(testAppToUpdateData).updateRoute();
-    }
-
-    public static Bundle insertSessionNoRouteAs(TestApp testAppToUpdateData) throws Exception {
-        return TestAppProxy.forApp(testAppToUpdateData).insertSessionNoRoute();
-    }
-
-    public static Bundle insertRecordWithAnotherAppPackageName(
-            TestApp testAppToInsertData, TestApp testAppPkgNameUsed) throws Exception {
-        return TestAppProxy.forApp(testAppToInsertData)
-                .insertRecordWithAnotherAppPackageName(testAppPkgNameUsed);
-    }
-
-    public static Bundle readRecordsAs(TestApp testApp, ArrayList<String> recordClassesToRead)
-            throws Exception {
-        return TestAppProxy.forApp(testApp).readRecords(recordClassesToRead);
-    }
-
-    public static Bundle readRecordsAs(
-            TestApp testApp,
-            ArrayList<String> recordClassesToRead,
-            Optional<List<String>> dataOriginFilterPackageNames)
-            throws Exception {
-        return TestAppProxy.forApp(testApp)
-                .readRecords(recordClassesToRead, dataOriginFilterPackageNames);
-    }
-
-    public static Bundle insertRecordWithGivenClientId(TestApp testApp, double clientId)
-            throws Exception {
-        return TestAppProxy.forApp(testApp).insertRecordWithGivenClientId(clientId);
-    }
-
-    public static Bundle readRecordsUsingDataOriginFiltersAs(
-            TestApp testApp, ArrayList<String> recordClassesToRead) throws Exception {
-        return TestAppProxy.forApp(testApp).readRecordsUsingDataOriginFilters(recordClassesToRead);
-    }
-
-    public static Bundle readChangeLogsUsingDataOriginFiltersAs(
-            TestApp testApp, String changeLogToken) throws Exception {
-        return TestAppProxy.forApp(testApp).readChangeLogsUsingDataOriginFilters(changeLogToken);
-    }
-
-    public static Bundle getChangeLogTokenAs(
-            TestApp testApp, String pkgName, ArrayList<String> recordClassesToRead)
-            throws Exception {
-        return TestAppProxy.forApp(testApp).getChangeLogToken(pkgName, recordClassesToRead);
-    }
-
-    public static Bundle insertStepsRecordAs(
-            TestApp testApp, String startTime, String endTime, int stepsCount) throws Exception {
-        return TestAppProxy.forApp(testApp).insertStepsRecord(startTime, endTime, stepsCount);
-    }
-
-    public static Bundle insertExerciseSessionAs(
-            TestApp testApp,
-            String sessionStartTime,
-            String sessionEndTime,
-            String pauseStart,
-            String pauseEnd)
-            throws Exception {
-        return TestAppProxy.forApp(testApp)
-                .insertExerciseSession(sessionStartTime, sessionEndTime, pauseStart, pauseEnd);
-    }
-
-    public static List<DataOrigin> getDataOriginPriorityOrder(TestApp testAppA, TestApp testAppB) {
-        return List.of(
-                new DataOrigin.Builder().setPackageName(testAppA.getPackageName()).build(),
-                new DataOrigin.Builder().setPackageName(testAppB.getPackageName()).build());
-    }
-}
diff --git a/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/TestAppProxy.java b/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/TestAppProxy.java
index 4003012..2ceecda 100644
--- a/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/TestAppProxy.java
+++ b/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/TestAppProxy.java
@@ -16,49 +16,30 @@
 
 package android.healthconnect.cts.lib;
 
-import static android.healthconnect.cts.lib.MultiAppTestUtils.APP_PKG_NAME_USED_IN_DATA_ORIGIN;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.CHANGE_LOG_TOKEN;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.CLIENT_ID;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.DATA_ORIGIN_FILTER_PACKAGE_NAMES;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.DELETE_RECORDS_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.END_TIME;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.EXERCISE_SESSION;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.GET_CHANGE_LOG_TOKEN_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.INSERT_RECORD_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.INTENT_EXCEPTION;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.INTENT_EXTRA_CALLING_PKG;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.PAUSE_END;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.PAUSE_START;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.QUERY_TYPE;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.READ_CHANGE_LOGS_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.READ_RECORDS_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.READ_RECORD_CLASS_NAME;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.READ_USING_DATA_ORIGIN_FILTERS;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.RECORD_IDS;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.RECORD_TYPE;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.START_TIME;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.STEPS_COUNT;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.STEPS_RECORD;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.UPDATE_EXERCISE_ROUTE;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.UPDATE_RECORDS_QUERY;
-import static android.healthconnect.cts.lib.MultiAppTestUtils.UPSERT_EXERCISE_ROUTE;
+import static android.healthconnect.cts.lib.BundleHelper.INTENT_EXCEPTION;
+import static android.healthconnect.cts.lib.BundleHelper.QUERY_TYPE;
 
 import static androidx.test.InstrumentationRegistry.getContext;
 
+import android.app.Instrumentation;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.ReadRecordsRequestUsingIds;
+import android.health.connect.RecordIdFilter;
+import android.health.connect.changelog.ChangeLogTokenRequest;
+import android.health.connect.changelog.ChangeLogsRequest;
+import android.health.connect.changelog.ChangeLogsResponse;
 import android.health.connect.datatypes.Record;
-import android.healthconnect.cts.utils.TestUtils;
+import android.healthconnect.cts.utils.ProxyActivity;
 import android.os.Bundle;
 
 import com.android.cts.install.lib.TestApp;
 
-import java.io.Serializable;
-import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
-import java.util.Optional;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
@@ -96,157 +77,102 @@
         return new TestAppProxy(packageName, true);
     }
 
-    /** Insert a few hardcoded records on behalf of the app. */
-    public Bundle insertRecord() throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, INSERT_RECORD_QUERY);
-
-        return getFromTestApp(bundle);
+    /** Returns the package name of the app. */
+    public String getPackageName() {
+        return mPackageName;
     }
 
-    /** Delete records on behalf of the app. */
-    public Bundle deleteRecords(List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass)
+    /** Inserts records to HC on behalf of the app. */
+    public List<String> insertRecords(Record... records) throws Exception {
+        return insertRecords(Arrays.asList(records));
+    }
+
+    /** Inserts records to HC on behalf of the app. */
+    public List<String> insertRecords(List<Record> records) throws Exception {
+        Bundle requestBundle = BundleHelper.fromInsertRecordsRequest(records);
+        Bundle responseBundle = getFromTestApp(requestBundle);
+        return BundleHelper.toInsertRecordsResponse(responseBundle);
+    }
+
+    /** Deletes records from HC on behalf of the app. */
+    public void deleteRecords(RecordIdFilter... recordIdFilters) throws Exception {
+        deleteRecords(Arrays.asList(recordIdFilters));
+    }
+
+    /** Deletes records from HC on behalf of the app. */
+    public void deleteRecords(List<RecordIdFilter> recordIdFilters) throws Exception {
+        Bundle requestBundle = BundleHelper.fromDeleteRecordsByIdsRequest(recordIdFilters);
+        getFromTestApp(requestBundle);
+    }
+
+    /** Updates records in HC on behalf of the app. */
+    public void updateRecords(Record... records) throws Exception {
+        updateRecords(Arrays.asList(records));
+    }
+
+    /** Updates records in HC on behalf of the app. */
+    public void updateRecords(List<Record> records) throws Exception {
+        Bundle requestBundle = BundleHelper.fromUpdateRecordsRequest(records);
+        getFromTestApp(requestBundle);
+    }
+
+    /** Read records from HC on behalf of the app. */
+    public <T extends Record> List<T> readRecords(ReadRecordsRequestUsingFilters<T> request)
             throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, DELETE_RECORDS_QUERY);
-        bundle.putSerializable(RECORD_IDS, (Serializable) listOfRecordIdsAndClass);
-
-        return getFromTestApp(bundle);
+        Bundle requestBundle = BundleHelper.fromReadRecordsRequestUsingFilters(request);
+        Bundle responseBundle = getFromTestApp(requestBundle);
+        return BundleHelper.toReadRecordsResponse(responseBundle);
     }
 
-    /** Update records on behalf of the app. */
-    public Bundle updateRecords(List<TestUtils.RecordTypeAndRecordIds> listOfRecordIdsAndClass)
+    /** Read records from HC on behalf of the app. */
+    public <T extends Record> List<T> readRecords(ReadRecordsRequestUsingIds<T> request)
             throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, UPDATE_RECORDS_QUERY);
-        bundle.putSerializable(RECORD_IDS, (Serializable) listOfRecordIdsAndClass);
-
-        return getFromTestApp(bundle);
+        Bundle requestBundle = BundleHelper.fromReadRecordsRequestUsingIds(request);
+        Bundle responseBundle = getFromTestApp(requestBundle);
+        return BundleHelper.toReadRecordsResponse(responseBundle);
     }
 
-    /** Update exercise route on behalf of the app. */
-    public Bundle updateRoute() throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, UPDATE_EXERCISE_ROUTE);
-        return getFromTestApp(bundle);
+    /** Gets changelogs from HC on behalf of the app. */
+    public ChangeLogsResponse getChangeLogs(ChangeLogsRequest request) throws Exception {
+        Bundle requestBundle = BundleHelper.fromChangeLogsRequest(request);
+        Bundle responseBundle = getFromTestApp(requestBundle);
+        return BundleHelper.toChangeLogsResponse(responseBundle);
     }
 
-    /** Insert an exercise session with a route on behalf of the app. */
-    public Bundle insertSessionNoRoute() throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, UPSERT_EXERCISE_ROUTE);
-        return getFromTestApp(bundle);
+    /** Gets a change log token from HC on behalf of the app. */
+    public String getChangeLogToken(ChangeLogTokenRequest request) throws Exception {
+        Bundle requestBundle = BundleHelper.fromChangeLogTokenRequest(request);
+        Bundle responseBundle = getFromTestApp(requestBundle);
+        return BundleHelper.toChangeLogTokenResponse(responseBundle);
     }
 
-    /** Insert a record with data origin set to given other app on behalf of the app. */
-    public Bundle insertRecordWithAnotherAppPackageName(TestApp testAppPkgNameUsed)
+    /** Starts an activity on behalf of the app and returns the result. */
+    public Instrumentation.ActivityResult startActivityForResult(Intent intent) throws Exception {
+        return startActivityForResult(intent, () -> {});
+    }
+
+    /**
+     * Starts an activity on behalf of the app, executes the runnable and returns the result.
+     *
+     * <p>The corresponding test app must have the following activity declared in the Manifest.
+     *
+     * <pre>{@code
+     * <activity android:name="android.healthconnect.cts.utils.ProxyActivity"
+     *           android:exported="true">
+     *   <intent-filter>
+     *      <action android:name="android.healthconnect.cts.ACTION_START_ACTIVITY_FOR_RESULT"/>
+     *      <category android:name="android.intent.category.DEFAULT"/>
+     *   </intent-filter>
+     * </activity>
+     * }</pre>
+     */
+    public Instrumentation.ActivityResult startActivityForResult(Intent intent, Runnable runnable)
             throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, INSERT_RECORD_QUERY);
-        bundle.putString(APP_PKG_NAME_USED_IN_DATA_ORIGIN, testAppPkgNameUsed.getPackageName());
+        Intent testAppIntent = new Intent(ProxyActivity.PROXY_ACTIVITY_ACTION);
+        testAppIntent.setPackage(mPackageName);
+        testAppIntent.putExtra(Intent.EXTRA_INTENT, intent);
 
-        return getFromTestApp(bundle);
-    }
-
-    /** Read records on behalf of the app. */
-    public Bundle readRecords(ArrayList<String> recordClassesToRead) throws Exception {
-        return readRecords(
-                recordClassesToRead, /* dataOriginFilterPackageNames= */ Optional.empty());
-    }
-
-    /** Read records on behalf of the app. */
-    public Bundle readRecords(Class<? extends Record> recordClassToRead) throws Exception {
-        return readRecords(
-                new ArrayList<>(List.of(recordClassToRead.getName())),
-                /* dataOriginFilterPackageNames= */ Optional.empty());
-    }
-
-    /** Read records on behalf of the app. */
-    public Bundle readRecords(
-            ArrayList<String> recordClassesToRead,
-            Optional<List<String>> dataOriginFilterPackageNames)
-            throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, READ_RECORDS_QUERY);
-        bundle.putStringArrayList(READ_RECORD_CLASS_NAME, recordClassesToRead);
-        if (!dataOriginFilterPackageNames.isEmpty()) {
-            ArrayList<String> dataOrigins = new ArrayList<>();
-            dataOrigins.addAll(dataOriginFilterPackageNames.get());
-            bundle.putBoolean(READ_USING_DATA_ORIGIN_FILTERS, true);
-            bundle.putStringArrayList(DATA_ORIGIN_FILTER_PACKAGE_NAMES, dataOrigins);
-        }
-        return getFromTestApp(bundle);
-    }
-
-    /** Insert a record with a given client id on behalf of the app. */
-    public Bundle insertRecordWithGivenClientId(double clientId) throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, INSERT_RECORD_QUERY);
-        bundle.putDouble(CLIENT_ID, clientId);
-
-        return getFromTestApp(bundle);
-    }
-
-    /** Read records using data origin filters on behalf of the app. */
-    public Bundle readRecordsUsingDataOriginFilters(ArrayList<String> recordClassesToRead)
-            throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, READ_RECORDS_QUERY);
-        bundle.putStringArrayList(READ_RECORD_CLASS_NAME, recordClassesToRead);
-        bundle.putBoolean(READ_USING_DATA_ORIGIN_FILTERS, true);
-
-        return getFromTestApp(bundle);
-    }
-
-    /** Read changelogs using data origin filters on behalf of the app. */
-    public Bundle readChangeLogsUsingDataOriginFilters(String changeLogToken) throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, READ_CHANGE_LOGS_QUERY);
-        bundle.putString(CHANGE_LOG_TOKEN, changeLogToken);
-        bundle.putBoolean(READ_USING_DATA_ORIGIN_FILTERS, true);
-
-        return getFromTestApp(bundle);
-    }
-
-    /** Get a changelogs token on behalf of the app. */
-    public Bundle getChangeLogToken(String pkgName, ArrayList<String> recordClassesToRead)
-            throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, GET_CHANGE_LOG_TOKEN_QUERY);
-        bundle.putString(APP_PKG_NAME_USED_IN_DATA_ORIGIN, pkgName);
-
-        if (recordClassesToRead != null) {
-            bundle.putStringArrayList(READ_RECORD_CLASS_NAME, recordClassesToRead);
-        }
-        return getFromTestApp(bundle);
-    }
-
-    /** Insert a steps record on behalf of the app. */
-    public Bundle insertStepsRecord(String startTime, String endTime, int stepsCount)
-            throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, INSERT_RECORD_QUERY);
-        bundle.putString(RECORD_TYPE, STEPS_RECORD);
-        bundle.putString(START_TIME, startTime);
-        bundle.putString(END_TIME, endTime);
-        bundle.putInt(STEPS_COUNT, stepsCount);
-
-        return getFromTestApp(bundle);
-    }
-
-    /** Insert an exercise session on behalf of the app. */
-    public Bundle insertExerciseSession(
-            String sessionStartTime, String sessionEndTime, String pauseStart, String pauseEnd)
-            throws Exception {
-        Bundle bundle = new Bundle();
-        bundle.putString(QUERY_TYPE, INSERT_RECORD_QUERY);
-        bundle.putString(RECORD_TYPE, EXERCISE_SESSION);
-        bundle.putString(START_TIME, sessionStartTime);
-        bundle.putString(END_TIME, sessionEndTime);
-        bundle.putString(PAUSE_START, pauseStart);
-        bundle.putString(PAUSE_END, pauseEnd);
-
-        return getFromTestApp(bundle);
+        return ProxyActivity.launchActivityForResult(testAppIntent, runnable);
     }
 
     private Bundle getFromTestApp(Bundle bundleToCreateIntent) throws Exception {
@@ -297,7 +223,6 @@
             intent.addCategory(Intent.CATEGORY_LAUNCHER);
         }
 
-        intent.putExtra(INTENT_EXTRA_CALLING_PKG, getContext().getPackageName());
         intent.putExtras(bundleToCreateIntent);
 
         Thread.sleep(500);
diff --git a/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/UiTestUtils.kt b/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/UiTestUtils.kt
index 78fda70..72c664c 100644
--- a/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/UiTestUtils.kt
+++ b/tests/cts/hostsidetests/healthconnect/libs/HealthConnectTestLib/src/android/healthconnect/cts/lib/UiTestUtils.kt
@@ -18,7 +18,6 @@
 import android.Manifest
 import android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
 import android.content.Context
-import android.content.pm.PackageManager
 import android.content.pm.PackageManager.PERMISSION_DENIED
 import android.content.pm.PackageManager.PERMISSION_GRANTED
 import android.health.connect.datatypes.*
@@ -27,14 +26,15 @@
 import android.util.Log
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.Direction
 import androidx.test.uiautomator.StaleObjectException
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.UiObject2
+import androidx.test.uiautomator.Until
 import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
 import com.android.compatibility.common.util.UiAutomatorUtils2.getUiDevice
 import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObject
 import com.android.compatibility.common.util.UiAutomatorUtils2.waitFindObjectOrNull
-import java.lang.Exception
 import java.time.Duration
 import java.time.Instant
 import java.util.concurrent.TimeoutException
@@ -52,7 +52,7 @@
     private val TAG = UiTestUtils::class.java.simpleName
 
     private val TEST_DEVICE: Device =
-            Device.Builder().setManufacturer("google").setModel("Pixel").setType(1).build()
+        Device.Builder().setManufacturer("google").setModel("Pixel").setType(1).build()
 
     private val PACKAGE_NAME = "android.healthconnect.cts.ui"
 
@@ -72,6 +72,18 @@
         }
     }
 
+    fun scrollDownTo(selector: BySelector) {
+        waitFindObject(By.scrollable(true)).scrollUntil(Direction.DOWN, Until.findObject(selector))
+    }
+
+    fun scrollDownToAndClick(selector: BySelector) {
+        getUiDevice()
+            .findObject(By.scrollable(true))
+            .scrollUntil(Direction.DOWN, Until.findObject(selector))
+            .click()
+        getUiDevice().waitForIdle()
+    }
+
     fun skipOnboardingIfAppears() {
         try {
             clickOnText("Get started")
@@ -145,7 +157,7 @@
      * [uiObjectAction] on it.
      */
     fun waitButtonDisplayed(label: CharSequence, uiObjectAction: (UiObject2) -> Unit = {}) =
-            waitDisplayed(buttonSelector(label), uiObjectAction)
+        waitDisplayed(buttonSelector(label), uiObjectAction)
 
     /** Waits for the given [selector] not to be displayed. */
     fun waitNotDisplayed(selector: BySelector) {
@@ -191,15 +203,15 @@
     }
 
     private fun waitFor(
-            message: String,
-            uiAutomatorConditionTimeout: Duration,
-            uiAutomatorCondition: (Duration) -> Boolean,
+        message: String,
+        uiAutomatorConditionTimeout: Duration,
+        uiAutomatorCondition: (Duration) -> Boolean,
     ) {
         val elapsedStartMillis = SystemClock.elapsedRealtime()
         while (true) {
             getUiDevice().waitForIdle()
             val durationSinceStart =
-                    Duration.ofMillis(SystemClock.elapsedRealtime() - elapsedStartMillis)
+                Duration.ofMillis(SystemClock.elapsedRealtime() - elapsedStartMillis)
             if (durationSinceStart >= WAIT_TIMEOUT) {
                 break
             }
@@ -229,7 +241,7 @@
 
     fun stepsRecordFromTestApp(startTime: Instant): StepsRecord {
         return stepsRecord(
-                TEST_APP_PACKAGE_NAME, /* stepCount= */ 10, startTime, startTime.plusSeconds(100))
+            TEST_APP_PACKAGE_NAME, /* stepCount= */ 10, startTime, startTime.plusSeconds(100))
     }
 
     fun stepsRecordFromTestApp(stepCount: Long, startTime: Instant): StepsRecord {
@@ -253,17 +265,17 @@
     }
 
     private fun stepsRecord(
-            packageName: String,
-            stepCount: Long,
-            startTime: Instant,
-            endTime: Instant
+        packageName: String,
+        stepCount: Long,
+        startTime: Instant,
+        endTime: Instant
     ): StepsRecord {
         val dataOrigin: DataOrigin = DataOrigin.Builder().setPackageName(packageName).build()
         val testMetadataBuilder: Metadata.Builder = Metadata.Builder()
         testMetadataBuilder.setDevice(TEST_DEVICE).setDataOrigin(dataOrigin)
         testMetadataBuilder.setClientRecordId("SR" + Math.random())
         return StepsRecord.Builder(testMetadataBuilder.build(), startTime, endTime, stepCount)
-                .build()
+            .build()
     }
 
     private fun distanceRecord(packageName: String): DistanceRecord {
@@ -276,7 +288,7 @@
                 Instant.now().minusMillis(1000),
                 Instant.now(),
                 Length.fromMeters(500.0))
-                .build()
+            .build()
     }
 
     fun grantPermissionViaPackageManager(context: Context, packageName: String, permName: String) {
@@ -285,8 +297,8 @@
             return
         }
         runWithShellPermissionIdentity(
-                { pm.grantRuntimePermission(packageName, permName, context.user) },
-                Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
+            { pm.grantRuntimePermission(packageName, permName, context.user) },
+            Manifest.permission.GRANT_RUNTIME_PERMISSIONS)
     }
 
     fun revokePermissionViaPackageManager(context: Context, packageName: String, permName: String) {
@@ -295,10 +307,7 @@
             return
         }
         runWithShellPermissionIdentity(
-                {
-                    pm.revokeRuntimePermission(
-                            packageName, permName, context.user, /* reason= */ "")
-                },
-                REVOKE_RUNTIME_PERMISSIONS)
+            { pm.revokeRuntimePermission(packageName, permName, context.user, /* reason= */ "") },
+            REVOKE_RUNTIME_PERMISSIONS)
     }
 }
diff --git a/tests/cts/route/Android.bp b/tests/cts/route/Android.bp
new file mode 100644
index 0000000..2a64c43
--- /dev/null
+++ b/tests/cts/route/Android.bp
@@ -0,0 +1,73 @@
+// Copyright (C) 2023 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+    name: "CtsExerciseRouteTestCases",
+    manifest: "AndroidManifest.xml",
+    test_config: "AndroidTest.xml",
+    defaults: ["cts_defaults"],
+    srcs: [
+        "src/**/*.java",
+        "src/**/*.kt"
+        ],
+    static_libs: [
+        "cts-healthconnect-lib",
+        "modules-utils-build_system",
+        "androidx.test.rules",
+        "androidx.test.ext.truth",
+        "compatibility-device-util-axt",
+        "ctstestrunner-axt",
+        "cts-wm-util",
+        "testng",
+        "cts-healthconnect-utils",
+    ],
+    test_suites: [
+        "cts",
+        "general-tests",
+        "mts-healthfitness",
+        "mcts-healthfitness",
+    ],
+    sdk_version: "test_current",
+    min_sdk_version: "34",
+    libs: [
+        "android.test.base",
+        "android.test.mock",
+        "android.test.runner",
+        "framework-healthfitness",
+    ],
+    data : [
+          ":CtsExerciseRouteTestRouteWriterApp",
+          ":CtsExerciseRouteTestRouteReaderWriterApp",
+    ]
+}
+
+android_test_helper_app {
+    name: "CtsExerciseRouteTestRouteWriterApp",
+    manifest: "RouteWriterAppManifest.xml",
+    static_libs: ["cts-healthconnect-lib", "cts-healthconnect-test-helper"],
+    sdk_version: "test_current",
+    min_sdk_version: "34",
+}
+
+android_test_helper_app {
+    name: "CtsExerciseRouteTestRouteReaderWriterApp",
+    manifest: "RouteReaderWriterAppManifest.xml",
+    static_libs: ["cts-healthconnect-lib", "cts-healthconnect-test-helper"],
+    sdk_version: "test_current",
+    min_sdk_version: "34",
+}
diff --git a/tests/cts/route/AndroidManifest.xml b/tests/cts/route/AndroidManifest.xml
new file mode 100644
index 0000000..b873f61
--- /dev/null
+++ b/tests/cts/route/AndroidManifest.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.healthconnect.cts.route">
+
+    <uses-permission android:name="android.permission.health.READ_EXERCISE"/>
+    <uses-permission android:name="android.permission.health.WRITE_EXERCISE"/>
+    <uses-permission android:name="android.permission.health.WRITE_EXERCISE_ROUTE"/>
+
+    <application android:label="Health Connect Exercise Route Tests">
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="Unused"
+            android:label="EmptyActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW_PERMISSION_USAGE"/>
+                <category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
+            </intent-filter>
+        </activity>
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:label="CTS HealthConnect tests"
+        android:targetPackage="android.healthconnect.cts.route">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener"/>
+    </instrumentation>
+
+    <queries>
+        <package android:name="android.healthconnect.cts.route.testapp.writer"/>
+        <package android:name="android.healthconnect.cts.route.testapp.readerWriter"/>
+    </queries>
+
+</manifest>
diff --git a/tests/cts/route/AndroidTest.xml b/tests/cts/route/AndroidTest.xml
new file mode 100644
index 0000000..cf7aef9
--- /dev/null
+++ b/tests/cts/route/AndroidTest.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 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.
+  -->
+<configuration description="Runs Health Connect exercise routes CTS tests.">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="framework" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="CtsExerciseRouteTestCases.apk" />
+        <option name="test-file-name" value="CtsExerciseRouteTestRouteWriterApp.apk" />
+        <option name="test-file-name" value="CtsExerciseRouteTestRouteReaderWriterApp.apk" />
+    </target_preparer>
+
+    <option
+        name="config-descriptor:metadata"
+        key="mainline-param"
+        value="com.google.android.healthfitness.apex" />
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.healthconnect.cts.route" />
+        <option name="hidden-api-checks" value="false" />
+    </test>
+
+    <object type="module_controller"
+            class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
+        <option name="mainline-module-package-name" value="com.google.android.healthfitness" />
+    </object>
+</configuration>
diff --git a/tests/cts/route/RouteReaderWriterAppManifest.xml b/tests/cts/route/RouteReaderWriterAppManifest.xml
new file mode 100644
index 0000000..3aeea26
--- /dev/null
+++ b/tests/cts/route/RouteReaderWriterAppManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2024 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.healthconnect.cts.route.testapp.readerWriter"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-permission android:name="android.permission-group.HEALTH"/>
+    <uses-permission android:name="android.permission.health.READ_EXERCISE"/>
+    <uses-permission android:name="android.permission.health.READ_EXERCISE_ROUTES"/>
+    <uses-permission android:name="android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND"/>
+    <uses-permission android:name="android.permission.health.WRITE_EXERCISE"/>
+    <uses-permission android:name="android.permission.health.WRITE_EXERCISE_ROUTE"/>
+
+    <application android:label="CtsExerciseRouteTestAllRoutesReaderApp">
+        <activity android:name="android.healthconnect.cts.testhelper.TestAppActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+                <action android:name="android.intent.action.VIEW_PERMISSION_USAGE"/>
+                <category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
+            </intent-filter>
+        </activity>
+
+        <activity android:name="android.healthconnect.cts.utils.ProxyActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.healthconnect.cts.ACTION_START_ACTIVITY_FOR_RESULT"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+        </activity>
+
+        <receiver android:name="android.healthconnect.cts.testhelper.TestAppReceiver"
+            android:exported="true"/>
+    </application>
+</manifest>
diff --git a/tests/cts/route/RouteWriterAppManifest.xml b/tests/cts/route/RouteWriterAppManifest.xml
new file mode 100644
index 0000000..ae9ba16
--- /dev/null
+++ b/tests/cts/route/RouteWriterAppManifest.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2023 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.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.healthconnect.cts.route.testapp.writer"
+    android:versionCode="1"
+    android:versionName="1.0">
+
+    <uses-permission android:name="android.permission-group.HEALTH"/>
+    <uses-permission android:name="android.permission.health.WRITE_EXERCISE"/>
+    <uses-permission android:name="android.permission.health.WRITE_EXERCISE_ROUTE"/>
+
+    <application android:label="CtsExerciseRouteTestRouteWriterApp">
+        <activity android:name="android.healthconnect.cts.testhelper.TestAppActivity"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+                <action android:name="android.intent.action.VIEW_PERMISSION_USAGE"/>
+                <category android:name="android.intent.category.HEALTH_PERMISSIONS"/>
+            </intent-filter>
+        </activity>
+
+        <receiver android:name="android.healthconnect.cts.testhelper.TestAppReceiver"
+            android:exported="true"/>
+    </application>
+</manifest>
diff --git a/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteBackgroundReadTest.java b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteBackgroundReadTest.java
new file mode 100644
index 0000000..88f393e
--- /dev/null
+++ b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteBackgroundReadTest.java
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts.route;
+
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.ROUTES_READER_WRITER_APP;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.ROUTE_WRITER_APP;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.assertCorrectHealthPermissions;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithRoute;
+import static android.healthconnect.cts.utils.DataFactory.getEmptyMetadata;
+import static android.healthconnect.cts.utils.TestUtils.connectAppsWithGrantedPermissions;
+import static android.healthconnect.cts.utils.TestUtils.deleteAllStagedRemoteData;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.ReadRecordsRequestUsingIds;
+import android.health.connect.changelog.ChangeLogTokenRequest;
+import android.health.connect.changelog.ChangeLogsRequest;
+import android.health.connect.changelog.ChangeLogsResponse;
+import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.healthconnect.cts.lib.TestAppProxy;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.DeviceConfigRule;
+import android.healthconnect.cts.utils.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class ExerciseRouteBackgroundReadTest {
+    private static final TestAppProxy ROUTES_READER_WRITER_BACKGROUND_APP =
+            TestAppProxy.forPackageNameInBackground(ROUTES_READER_WRITER_APP.getPackageName());
+
+    private static final String BACKGROUND_READ_FEATURE_FLAG = "background_read_enable";
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
+    @Rule
+    public DeviceConfigRule mDeviceConfigRule =
+            new DeviceConfigRule(BACKGROUND_READ_FEATURE_FLAG, "true");
+
+    @Before
+    public void setUp() {
+        assertCorrectHealthPermissions();
+        connectAppsWithGrantedPermissions();
+    }
+
+    @After
+    public void tearDown() throws InterruptedException {
+        deleteAllStagedRemoteData();
+    }
+
+    @Test
+    public void readRecords_usingFilters_cannotAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(sessionWithRoute);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_BACKGROUND_APP.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void readRecords_usingFilters_canAccessOwnRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTES_READER_WRITER_BACKGROUND_APP.insertRecords(sessionWithRoute);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_BACKGROUND_APP.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingFilters_mixedOwnAndOtherAppSession() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String otherAppSessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+        ExerciseSessionRecord ownSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String ownSessionId =
+                ROUTES_READER_WRITER_BACKGROUND_APP.insertRecords(List.of(ownSession)).get(0);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_BACKGROUND_APP.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+
+        Map<String, ExerciseSessionRecord> idToRecordMap =
+                records.stream()
+                        .collect(
+                                Collectors.toMap(
+                                        record -> record.getMetadata().getId(),
+                                        Function.identity()));
+        assertThat(records).hasSize(2);
+        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(otherAppSessionId).getRoute()).isNull();
+        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingIds_cannotAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_BACKGROUND_APP.readRecords(
+                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
+                                .addId(sessionId)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void readRecords_usingIds_canAccessOwnRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId =
+                ROUTES_READER_WRITER_BACKGROUND_APP.insertRecords(sessionWithRoute).get(0);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_BACKGROUND_APP.readRecords(
+                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
+                                .addId(sessionId)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingIds_mixedOwnAndOtherAppSession() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String otherAppSessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+        ExerciseSessionRecord ownSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String ownSessionId = ROUTES_READER_WRITER_BACKGROUND_APP.insertRecords(ownSession).get(0);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_BACKGROUND_APP.readRecords(
+                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
+                                .addId(otherAppSessionId)
+                                .addId(ownSessionId)
+                                .build());
+
+        Map<String, ExerciseSessionRecord> idToRecordMap =
+                records.stream()
+                        .collect(
+                                Collectors.toMap(
+                                        record -> record.getMetadata().getId(),
+                                        Function.identity()));
+        assertThat(records).hasSize(2);
+        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(otherAppSessionId).getRoute()).isNull();
+        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
+    }
+
+    @Test
+    public void getChangelogs_cannotAccessOtherAppRoute() throws Exception {
+        String token =
+                ROUTES_READER_WRITER_BACKGROUND_APP.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addRecordType(ExerciseSessionRecord.class)
+                                .build());
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(List.of(otherAppSession));
+
+        ChangeLogsResponse response =
+                ROUTES_READER_WRITER_BACKGROUND_APP.getChangeLogs(
+                        new ChangeLogsRequest.Builder(token).build());
+
+        List<ExerciseSessionRecord> records =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .toList();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void getChangelogs_canAccessOwnRoute() throws Exception {
+        String token =
+                ROUTES_READER_WRITER_BACKGROUND_APP.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addRecordType(ExerciseSessionRecord.class)
+                                .build());
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTES_READER_WRITER_BACKGROUND_APP.insertRecords(sessionWithRoute);
+
+        ChangeLogsResponse response =
+                ROUTES_READER_WRITER_BACKGROUND_APP.getChangeLogs(
+                        new ChangeLogsRequest.Builder(token).build());
+
+        List<ExerciseSessionRecord> records =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .toList();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void getChangelogs_mixedOwnAndOtherAppSession() throws Exception {
+        String token =
+                ROUTES_READER_WRITER_BACKGROUND_APP.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addRecordType(ExerciseSessionRecord.class)
+                                .build());
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String otherAppSessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+        ExerciseSessionRecord ownSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String ownSessionId = ROUTES_READER_WRITER_BACKGROUND_APP.insertRecords(ownSession).get(0);
+
+        ChangeLogsResponse response =
+                ROUTES_READER_WRITER_BACKGROUND_APP.getChangeLogs(
+                        new ChangeLogsRequest.Builder(token).build());
+
+        Map<String, ExerciseSessionRecord> idToRecordMap =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .collect(
+                                Collectors.toMap(
+                                        record -> record.getMetadata().getId(),
+                                        Function.identity()));
+        assertThat(response.getUpsertedRecords()).hasSize(2);
+        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(otherAppSessionId).getRoute()).isNull();
+        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
+    }
+}
diff --git a/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteManageHealthDataTest.java b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteManageHealthDataTest.java
new file mode 100644
index 0000000..880e4b9
--- /dev/null
+++ b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteManageHealthDataTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts.route;
+
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.ROUTE_WRITER_APP;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.assertCorrectHealthPermissions;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithRoute;
+import static android.healthconnect.cts.utils.DataFactory.getEmptyMetadata;
+import static android.healthconnect.cts.utils.PermissionHelper.MANAGE_HEALTH_DATA;
+import static android.healthconnect.cts.utils.TestUtils.deleteAllStagedRemoteData;
+import static android.healthconnect.cts.utils.TestUtils.getChangeLogToken;
+import static android.healthconnect.cts.utils.TestUtils.getChangeLogs;
+import static android.healthconnect.cts.utils.TestUtils.readRecords;
+
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.ReadRecordsRequestUsingIds;
+import android.health.connect.changelog.ChangeLogTokenRequest;
+import android.health.connect.changelog.ChangeLogsRequest;
+import android.health.connect.changelog.ChangeLogsResponse;
+import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+
+public class ExerciseRouteManageHealthDataTest {
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
+    @Before
+    public void setUp() throws Exception {
+        assertCorrectHealthPermissions();
+    }
+
+    @After
+    public void tearDown() throws InterruptedException {
+        deleteAllStagedRemoteData();
+    }
+
+    @Test
+    public void readRecords_usingFilters_canNotAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(sessionWithRoute);
+
+        List<ExerciseSessionRecord> records =
+                runWithShellPermissionIdentity(
+                        () ->
+                                readRecords(
+                                        new ReadRecordsRequestUsingFilters.Builder<>(
+                                                        ExerciseSessionRecord.class)
+                                                .build()),
+                        MANAGE_HEALTH_DATA);
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void readRecords_usingIds_canNotAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+
+        List<ExerciseSessionRecord> records =
+                runWithShellPermissionIdentity(
+                        () ->
+                                readRecords(
+                                        new ReadRecordsRequestUsingIds.Builder<>(
+                                                        ExerciseSessionRecord.class)
+                                                .addId(sessionId)
+                                                .build()),
+                        MANAGE_HEALTH_DATA);
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void getChangelogs_canNotAccessOtherAppRoute() throws Exception {
+        String token =
+                getChangeLogToken(
+                                new ChangeLogTokenRequest.Builder()
+                                        .addRecordType(ExerciseSessionRecord.class)
+                                        .build())
+                        .getToken();
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(otherAppSession);
+
+        ChangeLogsResponse response =
+                runWithShellPermissionIdentity(
+                        () -> getChangeLogs(new ChangeLogsRequest.Builder(token).build()),
+                        MANAGE_HEALTH_DATA);
+
+        List<ExerciseSessionRecord> records =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .toList();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+}
diff --git a/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteNoReadWritePermissionTest.java b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteNoReadWritePermissionTest.java
new file mode 100644
index 0000000..b56a664
--- /dev/null
+++ b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteNoReadWritePermissionTest.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts.route;
+
+import static android.health.connect.HealthPermissions.WRITE_EXERCISE_ROUTE;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.ROUTES_READER_WRITER_APP;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.ROUTE_WRITER_APP;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.assertCorrectHealthPermissions;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithAnotherRoute;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithRoute;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithoutRoute;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.readAllExerciseSessionRecordsPrivileged;
+import static android.healthconnect.cts.utils.DataFactory.getEmptyMetadata;
+import static android.healthconnect.cts.utils.DataFactory.getMetadataForClientId;
+import static android.healthconnect.cts.utils.DataFactory.getMetadataForId;
+import static android.healthconnect.cts.utils.PermissionHelper.READ_EXERCISE_ROUTES;
+import static android.healthconnect.cts.utils.PermissionHelper.runWithRevokedPermissions;
+import static android.healthconnect.cts.utils.TestUtils.connectAppsWithGrantedPermissions;
+import static android.healthconnect.cts.utils.TestUtils.deleteAllStagedRemoteData;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.health.connect.HealthConnectException;
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.ReadRecordsRequestUsingIds;
+import android.health.connect.changelog.ChangeLogTokenRequest;
+import android.health.connect.changelog.ChangeLogsRequest;
+import android.health.connect.changelog.ChangeLogsResponse;
+import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+
+public class ExerciseRouteNoReadWritePermissionTest {
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
+    @Before
+    public void setUp() throws Exception {
+        assertCorrectHealthPermissions();
+        connectAppsWithGrantedPermissions();
+    }
+
+    @After
+    public void tearDown() throws InterruptedException {
+        deleteAllStagedRemoteData();
+    }
+
+    @Test
+    public void insertRecords_canNotInsertRoute() {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () ->
+                                runWithRevokedPermissions(
+                                        () -> ROUTE_WRITER_APP.insertRecords(otherAppSession),
+                                        ROUTE_WRITER_APP.getPackageName(),
+                                        WRITE_EXERCISE_ROUTE));
+
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
+    }
+
+    @Test
+    public void insertRecords_withSameClientId_withoutRoute_routeDoesNotGetDeleted()
+            throws Exception {
+        ExerciseSessionRecord sessionWithRoute =
+                getExerciseSessionWithRoute(getMetadataForClientId("client id"));
+        ROUTE_WRITER_APP.insertRecords(sessionWithRoute);
+        ExerciseSessionRecord updatedSessionWithoutRoute =
+                getExerciseSessionWithoutRoute(getMetadataForClientId("client id"));
+
+        runWithRevokedPermissions(
+                () -> ROUTE_WRITER_APP.insertRecords(updatedSessionWithoutRoute),
+                ROUTE_WRITER_APP.getPackageName(),
+                WRITE_EXERCISE_ROUTE);
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void insertRecords_withSameClientId_updatedRoute_throws_routeDoesNotGetUpdated()
+            throws Exception {
+        ExerciseSessionRecord sessionWithRoute =
+                getExerciseSessionWithRoute(getMetadataForClientId("client id"));
+        ROUTE_WRITER_APP.insertRecords(sessionWithRoute);
+        ExerciseSessionRecord sessionWithUpdatedRoute =
+                getExerciseSessionWithAnotherRoute(getMetadataForClientId("client id"));
+
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () ->
+                                runWithRevokedPermissions(
+                                        () ->
+                                                ROUTE_WRITER_APP.insertRecords(
+                                                        sessionWithUpdatedRoute),
+                                        ROUTE_WRITER_APP.getPackageName(),
+                                        WRITE_EXERCISE_ROUTE));
+
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void insertRecords_withSameClientId_addedRoute_throws_routeDoesNotGetAdded()
+            throws Exception {
+        ExerciseSessionRecord sessionWithoutRoute =
+                getExerciseSessionWithoutRoute(getMetadataForClientId("client id"));
+        ROUTE_WRITER_APP.insertRecords(sessionWithoutRoute);
+        ExerciseSessionRecord sessionWithAddedRoute =
+                getExerciseSessionWithRoute(getMetadataForClientId("client id"));
+
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () ->
+                                runWithRevokedPermissions(
+                                        () -> ROUTE_WRITER_APP.insertRecords(sessionWithAddedRoute),
+                                        ROUTE_WRITER_APP.getPackageName(),
+                                        WRITE_EXERCISE_ROUTE));
+
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isFalse();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void updateRecords_withoutRoute_routeDoesNotGetDeleted() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = ROUTE_WRITER_APP.insertRecords(sessionWithRoute).get(0);
+        ExerciseSessionRecord updatedSessionWithoutRoute =
+                getExerciseSessionWithoutRoute(getMetadataForId(sessionId));
+
+        runWithRevokedPermissions(
+                ROUTE_WRITER_APP.getPackageName(),
+                WRITE_EXERCISE_ROUTE,
+                () -> ROUTE_WRITER_APP.updateRecords(updatedSessionWithoutRoute));
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void updateRecords_withUpdatedRoute_throws_routeDoesNotGetUpdated() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = ROUTE_WRITER_APP.insertRecords(sessionWithRoute).get(0);
+        ExerciseSessionRecord sessionWithUpdatedRoute =
+                getExerciseSessionWithAnotherRoute(getMetadataForId(sessionId));
+
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () ->
+                                runWithRevokedPermissions(
+                                        ROUTE_WRITER_APP.getPackageName(),
+                                        WRITE_EXERCISE_ROUTE,
+                                        () ->
+                                                ROUTE_WRITER_APP.updateRecords(
+                                                        sessionWithUpdatedRoute)));
+
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void updateRecords_withAddedRoute_throws_routeDoesNotGetAdded() throws Exception {
+        ExerciseSessionRecord sessionWithoutRoute =
+                getExerciseSessionWithoutRoute(getEmptyMetadata());
+        String sessionId = ROUTE_WRITER_APP.insertRecords(sessionWithoutRoute).get(0);
+        ExerciseSessionRecord sessionWithAddedRoute =
+                getExerciseSessionWithRoute(getMetadataForId(sessionId));
+
+        HealthConnectException e =
+                assertThrows(
+                        HealthConnectException.class,
+                        () ->
+                                runWithRevokedPermissions(
+                                        ROUTE_WRITER_APP.getPackageName(),
+                                        WRITE_EXERCISE_ROUTE,
+                                        () ->
+                                                ROUTE_WRITER_APP.updateRecords(
+                                                        sessionWithAddedRoute)));
+
+        assertThat(e.getErrorCode()).isEqualTo(HealthConnectException.ERROR_SECURITY);
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isFalse();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    // TODO(b/319821477): disallow reading own routes without any granted ER permission.
+    @Test
+    public void readRecords_usingFilters_canAccessOwnRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTES_READER_WRITER_APP.insertRecords(sessionWithRoute);
+
+        List<ExerciseSessionRecord> records =
+                runWithRevokedPermissions(
+                        () ->
+                                ROUTES_READER_WRITER_APP.readRecords(
+                                        new ReadRecordsRequestUsingFilters.Builder<>(
+                                                        ExerciseSessionRecord.class)
+                                                .build()),
+                        ROUTES_READER_WRITER_APP.getPackageName(),
+                        READ_EXERCISE_ROUTES,
+                        WRITE_EXERCISE_ROUTE);
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    // TODO(b/319821477): disallow reading own routes without any granted ER permission.
+    @Test
+    public void readRecords_usingIds_canAccessOwnRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = ROUTES_READER_WRITER_APP.insertRecords(sessionWithRoute).get(0);
+
+        List<ExerciseSessionRecord> records =
+                runWithRevokedPermissions(
+                        () ->
+                                ROUTES_READER_WRITER_APP.readRecords(
+                                        new ReadRecordsRequestUsingIds.Builder<>(
+                                                        ExerciseSessionRecord.class)
+                                                .addId(sessionId)
+                                                .build()),
+                        ROUTES_READER_WRITER_APP.getPackageName(),
+                        READ_EXERCISE_ROUTES,
+                        WRITE_EXERCISE_ROUTE);
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    // TODO(b/319821477): disallow reading own routes without any granted ER permission.
+    @Test
+    public void getChangelogs_canAccessOwnRoute() throws Exception {
+        String token =
+                ROUTES_READER_WRITER_APP.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addRecordType(ExerciseSessionRecord.class)
+                                .build());
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTES_READER_WRITER_APP.insertRecords(sessionWithRoute);
+
+        ChangeLogsResponse response =
+                runWithRevokedPermissions(
+                        () ->
+                                ROUTES_READER_WRITER_APP.getChangeLogs(
+                                        new ChangeLogsRequest.Builder(token).build()),
+                        ROUTES_READER_WRITER_APP.getPackageName(),
+                        READ_EXERCISE_ROUTES,
+                        WRITE_EXERCISE_ROUTE);
+
+        List<ExerciseSessionRecord> records =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .toList();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+}
diff --git a/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteReadAllFeatureOffTest.java b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteReadAllFeatureOffTest.java
new file mode 100644
index 0000000..00ca322
--- /dev/null
+++ b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteReadAllFeatureOffTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts.route;
+
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.ROUTES_READER_WRITER_APP;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.ROUTE_WRITER_APP;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.assertCorrectHealthPermissions;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithRoute;
+import static android.healthconnect.cts.utils.DataFactory.getEmptyMetadata;
+import static android.healthconnect.cts.utils.TestUtils.connectAppsWithGrantedPermissions;
+import static android.healthconnect.cts.utils.TestUtils.deleteAllStagedRemoteData;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.ReadRecordsRequestUsingIds;
+import android.health.connect.changelog.ChangeLogTokenRequest;
+import android.health.connect.changelog.ChangeLogsRequest;
+import android.health.connect.changelog.ChangeLogsResponse;
+import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.DeviceConfigRule;
+import android.healthconnect.cts.utils.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+
+public class ExerciseRouteReadAllFeatureOffTest {
+    private static final String READ_ROUTES_ALL_FEATURE_FLAG = "exercise_routes_read_all_enable";
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
+    @Rule
+    public DeviceConfigRule mDeviceConfigRule =
+            new DeviceConfigRule(READ_ROUTES_ALL_FEATURE_FLAG, "false");
+
+    @Before
+    public void setUp() throws Exception {
+        assertCorrectHealthPermissions();
+        connectAppsWithGrantedPermissions();
+    }
+
+    @After
+    public void tearDown() throws InterruptedException {
+        deleteAllStagedRemoteData();
+    }
+
+    @Test
+    public void readRecords_usingFilters_canNotAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(sessionWithRoute);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_APP.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void readRecords_usingFilters_canAccessOwnRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTES_READER_WRITER_APP.insertRecords(List.of(sessionWithRoute));
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_APP.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingIds_canNotAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_APP.readRecords(
+                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
+                                .addId(sessionId)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void readRecords_usingIds_canAccessOwnRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = ROUTES_READER_WRITER_APP.insertRecords(sessionWithRoute).get(0);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_APP.readRecords(
+                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
+                                .addId(sessionId)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void getChangelogs_canNotAccessOtherAppRoute() throws Exception {
+        String token =
+                ROUTES_READER_WRITER_APP.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addRecordType(ExerciseSessionRecord.class)
+                                .build());
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(otherAppSession);
+
+        ChangeLogsResponse response =
+                ROUTES_READER_WRITER_APP.getChangeLogs(
+                        new ChangeLogsRequest.Builder(token).build());
+
+        List<ExerciseSessionRecord> records =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .toList();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void getChangelogs_canAccessOwnRoute() throws Exception {
+        String token =
+                ROUTES_READER_WRITER_APP.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addRecordType(ExerciseSessionRecord.class)
+                                .build());
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTES_READER_WRITER_APP.insertRecords(sessionWithRoute);
+
+        ChangeLogsResponse response =
+                ROUTES_READER_WRITER_APP.getChangeLogs(
+                        new ChangeLogsRequest.Builder(token).build());
+
+        List<ExerciseSessionRecord> records =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .toList();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+}
diff --git a/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteReadTest.java b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteReadTest.java
new file mode 100644
index 0000000..3c21277
--- /dev/null
+++ b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteReadTest.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts.route;
+
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.ROUTE_WRITER_APP;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.assertCorrectHealthPermissions;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithRoute;
+import static android.healthconnect.cts.utils.DataFactory.getEmptyMetadata;
+import static android.healthconnect.cts.utils.TestUtils.connectAppsWithGrantedPermissions;
+import static android.healthconnect.cts.utils.TestUtils.deleteAllStagedRemoteData;
+import static android.healthconnect.cts.utils.TestUtils.getChangeLogToken;
+import static android.healthconnect.cts.utils.TestUtils.getChangeLogs;
+import static android.healthconnect.cts.utils.TestUtils.insertRecords;
+import static android.healthconnect.cts.utils.TestUtils.readRecords;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.ReadRecordsRequestUsingIds;
+import android.health.connect.changelog.ChangeLogTokenRequest;
+import android.health.connect.changelog.ChangeLogsRequest;
+import android.health.connect.changelog.ChangeLogsResponse;
+import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class ExerciseRouteReadTest {
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
+    @Before
+    public void setUp() throws Exception {
+        assertCorrectHealthPermissions();
+        connectAppsWithGrantedPermissions();
+    }
+
+    @After
+    public void tearDown() throws InterruptedException {
+        deleteAllStagedRemoteData();
+    }
+
+    @Test
+    public void readRecords_usingFilters_cannotAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(sessionWithRoute);
+
+        List<ExerciseSessionRecord> records =
+                readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void readRecords_usingFilters_canAccessOwnRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        insertRecords(List.of(sessionWithRoute));
+
+        List<ExerciseSessionRecord> records =
+                readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingFilters_mixedOwnAndOtherAppSession() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String otherAppSessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+        ExerciseSessionRecord ownSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String ownSessionId = insertRecords(List.of(ownSession)).get(0).getMetadata().getId();
+
+        List<ExerciseSessionRecord> records =
+                readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+
+        Map<String, ExerciseSessionRecord> idToRecordMap =
+                records.stream()
+                        .collect(
+                                Collectors.toMap(
+                                        record -> record.getMetadata().getId(),
+                                        Function.identity()));
+        assertThat(records).hasSize(2);
+        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(otherAppSessionId).getRoute()).isNull();
+        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingIds_cannotAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+
+        List<ExerciseSessionRecord> records =
+                readRecords(
+                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
+                                .addId(sessionId)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void readRecords_usingIds_canAccessOwnRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = insertRecords(List.of(sessionWithRoute)).get(0).getMetadata().getId();
+
+        List<ExerciseSessionRecord> records =
+                readRecords(
+                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
+                                .addId(sessionId)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingIds_mixedOwnAndOtherAppSession() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String otherAppSessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+        ExerciseSessionRecord ownSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String ownSessionId = insertRecords(List.of(ownSession)).get(0).getMetadata().getId();
+
+        List<ExerciseSessionRecord> records =
+                readRecords(
+                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
+                                .addId(otherAppSessionId)
+                                .addId(ownSessionId)
+                                .build());
+
+        Map<String, ExerciseSessionRecord> idToRecordMap =
+                records.stream()
+                        .collect(
+                                Collectors.toMap(
+                                        record -> record.getMetadata().getId(),
+                                        Function.identity()));
+        assertThat(records).hasSize(2);
+        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(otherAppSessionId).getRoute()).isNull();
+        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
+    }
+
+    @Test
+    public void getChangelogs_cannotAccessOtherAppRoute() throws Exception {
+        String token =
+                getChangeLogToken(
+                                new ChangeLogTokenRequest.Builder()
+                                        .addRecordType(ExerciseSessionRecord.class)
+                                        .build())
+                        .getToken();
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(List.of(otherAppSession));
+
+        ChangeLogsResponse response = getChangeLogs(new ChangeLogsRequest.Builder(token).build());
+
+        List<ExerciseSessionRecord> records =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .toList();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void getChangelogs_canAccessOwnRoute() throws Exception {
+        String token =
+                getChangeLogToken(
+                                new ChangeLogTokenRequest.Builder()
+                                        .addRecordType(ExerciseSessionRecord.class)
+                                        .build())
+                        .getToken();
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        insertRecords(List.of(sessionWithRoute));
+
+        ChangeLogsResponse response = getChangeLogs(new ChangeLogsRequest.Builder(token).build());
+
+        List<ExerciseSessionRecord> records =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .toList();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void getChangelogs_mixedOwnAndOtherAppSession() throws Exception {
+        String token =
+                getChangeLogToken(
+                                new ChangeLogTokenRequest.Builder()
+                                        .addRecordType(ExerciseSessionRecord.class)
+                                        .build())
+                        .getToken();
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String otherAppSessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+        ExerciseSessionRecord ownSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String ownSessionId = insertRecords(List.of(ownSession)).get(0).getMetadata().getId();
+
+        ChangeLogsResponse response = getChangeLogs(new ChangeLogsRequest.Builder(token).build());
+
+        Map<String, ExerciseSessionRecord> idToRecordMap =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .collect(
+                                Collectors.toMap(
+                                        record -> record.getMetadata().getId(),
+                                        Function.identity()));
+        assertThat(response.getUpsertedRecords()).isNotNull();
+        assertThat(response.getUpsertedRecords()).hasSize(2);
+        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(otherAppSessionId).getRoute()).isNull();
+        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
+    }
+}
diff --git a/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteTestHelper.java b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteTestHelper.java
new file mode 100644
index 0000000..45330f3
--- /dev/null
+++ b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteTestHelper.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2024 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 android.healthconnect.cts.route;
+
+import static android.health.connect.HealthPermissions.READ_EXERCISE;
+import static android.health.connect.HealthPermissions.WRITE_EXERCISE;
+import static android.health.connect.HealthPermissions.WRITE_EXERCISE_ROUTE;
+import static android.healthconnect.cts.utils.PermissionHelper.READ_EXERCISE_ROUTES;
+import static android.healthconnect.cts.utils.PermissionHelper.READ_EXERCISE_ROUTE_PERMISSION;
+import static android.healthconnect.cts.utils.PermissionHelper.READ_HEALTH_DATA_IN_BACKGROUND;
+import static android.healthconnect.cts.utils.PermissionHelper.getGrantedHealthPermissions;
+import static android.healthconnect.cts.utils.TestUtils.readRecords;
+import static android.healthconnect.cts.utils.TestUtils.yesterdayAt;
+
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static java.time.Duration.ofMinutes;
+
+import android.content.Context;
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.datatypes.ExerciseRoute;
+import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.health.connect.datatypes.ExerciseSessionType;
+import android.health.connect.datatypes.Metadata;
+import android.health.connect.datatypes.units.Length;
+import android.healthconnect.cts.lib.TestAppProxy;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+
+final class ExerciseRouteTestHelper {
+
+    static final TestAppProxy ROUTE_WRITER_APP =
+            TestAppProxy.forPackageName("android.healthconnect.cts.route.testapp.writer");
+
+    static final TestAppProxy ROUTES_READER_WRITER_APP =
+            TestAppProxy.forPackageName("android.healthconnect.cts.route.testapp.readerWriter");
+
+    static final Instant START_TIME = yesterdayAt("11:00").truncatedTo(ChronoUnit.MILLIS);
+
+    /**
+     * Make sure test app permissions didn't change between the runs.
+     *
+     * <p>Fail quickly and explicitly if the permissions were not cleaned up by a previous test
+     * case. Also because permissions in CTS tests are auto granted it's easy to misconfigure
+     * permissions without noticing it, so this works as a double check.
+     */
+    static void assertCorrectHealthPermissions() {
+        Context context = ApplicationProvider.getApplicationContext();
+        assertThat(getGrantedHealthPermissions(context.getPackageName()))
+                .containsExactly(READ_EXERCISE, WRITE_EXERCISE, WRITE_EXERCISE_ROUTE);
+        assertThat(getGrantedHealthPermissions(ROUTE_WRITER_APP.getPackageName()))
+                .containsExactly(WRITE_EXERCISE, WRITE_EXERCISE_ROUTE);
+        assertThat(getGrantedHealthPermissions(ROUTES_READER_WRITER_APP.getPackageName()))
+                .containsExactly(
+                        READ_EXERCISE,
+                        READ_EXERCISE_ROUTES,
+                        READ_HEALTH_DATA_IN_BACKGROUND,
+                        WRITE_EXERCISE,
+                        WRITE_EXERCISE_ROUTE);
+    }
+
+    static ExerciseSessionRecord getExerciseSessionWithRoute(Metadata metadata) {
+        return getExerciseSessionWithRoute(metadata, START_TIME);
+    }
+
+    static ExerciseSessionRecord getExerciseSessionWithRoute(Metadata metadata, Instant startTime) {
+        return getExerciseSession(metadata, startTime, getRoute(startTime));
+    }
+
+    static ExerciseSessionRecord getExerciseSessionWithAnotherRoute(Metadata metadata) {
+        return getExerciseSession(metadata, START_TIME, getAnotherRoute(START_TIME));
+    }
+
+    static ExerciseSessionRecord getExerciseSessionWithoutRoute(Metadata metadata) {
+        return getExerciseSession(metadata, START_TIME, null);
+    }
+
+    static ExerciseSessionRecord getExerciseSessionWithoutRoute(
+            Metadata metadata, Instant startTime) {
+        return getExerciseSession(metadata, startTime, null);
+    }
+
+    static ExerciseSessionRecord getExerciseSession(
+            Metadata metadata, Instant startTime, ExerciseRoute route) {
+        return new ExerciseSessionRecord.Builder(
+                        metadata,
+                        startTime,
+                        startTime.plus(ofMinutes(30)),
+                        ExerciseSessionType.EXERCISE_SESSION_TYPE_RUNNING)
+                .setRoute(route)
+                .build();
+    }
+
+    static ExerciseRoute getRoute(Instant startTime) {
+        return new ExerciseRoute(
+                List.of(
+                        new ExerciseRoute.Location.Builder(startTime, 52., 48.).build(),
+                        new ExerciseRoute.Location.Builder(startTime.plusSeconds(5), -51., -49.)
+                                .setAltitude(Length.fromMeters(14))
+                                .setHorizontalAccuracy(Length.fromMeters(3))
+                                .setVerticalAccuracy(Length.fromMeters(5))
+                                .build()));
+    }
+
+    static ExerciseRoute getAnotherRoute(Instant startTime) {
+        return new ExerciseRoute(
+                List.of(
+                        new ExerciseRoute.Location.Builder(startTime.plusSeconds(10), -53., -47.)
+                                .setAltitude(Length.fromMeters(123))
+                                .setHorizontalAccuracy(Length.fromMeters(7))
+                                .setVerticalAccuracy(Length.fromMeters(11))
+                                .build()));
+    }
+
+    static List<ExerciseSessionRecord> readAllExerciseSessionRecordsPrivileged() {
+        return runWithShellPermissionIdentity(
+                () ->
+                        readRecords(
+                                new ReadRecordsRequestUsingFilters.Builder<>(
+                                                ExerciseSessionRecord.class)
+                                        .build()),
+                READ_EXERCISE_ROUTE_PERMISSION);
+    }
+
+    private ExerciseRouteTestHelper() {}
+}
diff --git a/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteWriteTest.java b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteWriteTest.java
new file mode 100644
index 0000000..0c805f7
--- /dev/null
+++ b/tests/cts/route/src/android/healthconnect/cts/route/ExerciseRouteWriteTest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts.route;
+
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.assertCorrectHealthPermissions;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getAnotherRoute;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSession;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithAnotherRoute;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithRoute;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithoutRoute;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getRoute;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.readAllExerciseSessionRecordsPrivileged;
+import static android.healthconnect.cts.utils.DataFactory.getEmptyMetadata;
+import static android.healthconnect.cts.utils.DataFactory.getMetadataForClientId;
+import static android.healthconnect.cts.utils.DataFactory.getMetadataForClientIdAndVersion;
+import static android.healthconnect.cts.utils.DataFactory.getMetadataForId;
+import static android.healthconnect.cts.utils.TestUtils.connectAppsWithGrantedPermissions;
+import static android.healthconnect.cts.utils.TestUtils.deleteAllStagedRemoteData;
+import static android.healthconnect.cts.utils.TestUtils.insertRecords;
+import static android.healthconnect.cts.utils.TestUtils.updateRecords;
+import static android.healthconnect.cts.utils.TestUtils.yesterdayAt;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class ExerciseRouteWriteTest {
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
+    @Before
+    public void setUp() throws Exception {
+        assertCorrectHealthPermissions();
+        connectAppsWithGrantedPermissions();
+    }
+
+    @After
+    public void tearDown() throws InterruptedException {
+        deleteAllStagedRemoteData();
+    }
+
+    @Test
+    public void insertRecords_withRoute_routeGetsInserted() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+
+        insertRecords(List.of(sessionWithRoute));
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void insertRecords_withClientId_withoutRoute_routeGetsDeleted() throws Exception {
+        ExerciseSessionRecord sessionWithRoute =
+                getExerciseSessionWithRoute(getMetadataForClientId("client id"));
+        insertRecords(List.of(sessionWithRoute));
+        ExerciseSessionRecord updatedSessionWithoutRoute =
+                getExerciseSessionWithoutRoute(getMetadataForClientId("client id"));
+
+        insertRecords(List.of(updatedSessionWithoutRoute));
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isFalse();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void insertRecords_withClientId_withUpdatedRoute_routeGetsUpdated() throws Exception {
+        ExerciseSessionRecord sessionWithRoute =
+                getExerciseSessionWithRoute(getMetadataForClientId("client id"));
+        insertRecords(List.of(sessionWithRoute));
+        ExerciseSessionRecord sessionWithUpdatedRoute =
+                getExerciseSessionWithAnotherRoute(getMetadataForClientId("client id"));
+
+        insertRecords(List.of(sessionWithUpdatedRoute));
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithUpdatedRoute.getRoute());
+    }
+
+    @Test
+    public void insertRecords_withClientId_withAddedRoute_routeGetsInserted() throws Exception {
+        ExerciseSessionRecord sessionWithoutRoute =
+                getExerciseSessionWithoutRoute(getMetadataForClientId("client id"));
+        insertRecords(List.of(sessionWithoutRoute));
+        ExerciseSessionRecord updatedSessionWithRoute =
+                getExerciseSessionWithRoute(getMetadataForClientId("client id"));
+
+        insertRecords(List.of(updatedSessionWithRoute));
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(updatedSessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void insertRecords_withClientId_withHigherVersionId_routeGetsUpdated() throws Exception {
+        ExerciseSessionRecord sessionWithRoute =
+                getExerciseSessionWithRoute(getMetadataForClientIdAndVersion("client id", 5));
+        insertRecords(List.of(sessionWithRoute));
+        ExerciseSessionRecord sessionWithUpdatedRoute =
+                getExerciseSessionWithAnotherRoute(
+                        getMetadataForClientIdAndVersion("client id", 6));
+
+        insertRecords(List.of(sessionWithUpdatedRoute));
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithUpdatedRoute.getRoute());
+    }
+
+    @Test
+    public void insertRecords_withClientId_withSameVersionId_routeGetsUpdated() throws Exception {
+        ExerciseSessionRecord sessionWithRoute =
+                getExerciseSessionWithRoute(getMetadataForClientIdAndVersion("client id", 5));
+        insertRecords(List.of(sessionWithRoute));
+        ExerciseSessionRecord sessionWithUpdatedRoute =
+                getExerciseSessionWithAnotherRoute(
+                        getMetadataForClientIdAndVersion("client id", 5));
+
+        insertRecords(List.of(sessionWithUpdatedRoute));
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithUpdatedRoute.getRoute());
+    }
+
+    @Test
+    public void insertRecords_withClientId_withLowerVersionId_routeDoesNotGetUpdated()
+            throws Exception {
+        ExerciseSessionRecord sessionWithRoute =
+                getExerciseSessionWithRoute(getMetadataForClientIdAndVersion("client id", 5));
+        insertRecords(List.of(sessionWithRoute));
+        ExerciseSessionRecord sessionWithUpdatedRoute =
+                getExerciseSessionWithAnotherRoute(
+                        getMetadataForClientIdAndVersion("client id", 4));
+
+        insertRecords(List.of(sessionWithUpdatedRoute));
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void updateRecords_withoutRoute_routeGetsDeleted() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        String exerciseRecordId =
+                insertRecords(List.of(sessionWithRoute)).get(0).getMetadata().getId();
+        ExerciseSessionRecord updatedSessionWithoutRoute =
+                getExerciseSessionWithoutRoute(getMetadataForId(exerciseRecordId));
+
+        updateRecords(List.of(updatedSessionWithoutRoute));
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isFalse();
+        assertThat(records.get(0).getRoute()).isNull();
+    }
+
+    @Test
+    public void updateRecords_withRoute_routeGetsInserted() throws Exception {
+        ExerciseSessionRecord sessionWithoutRoute =
+                getExerciseSessionWithoutRoute(getEmptyMetadata());
+        String exerciseRecordId =
+                insertRecords(List.of(sessionWithoutRoute)).get(0).getMetadata().getId();
+        ExerciseSessionRecord updatedSessionWithRoute =
+                getExerciseSessionWithRoute(getMetadataForId(exerciseRecordId));
+
+        updateRecords(List.of(updatedSessionWithRoute));
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(updatedSessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void updateRecords_withUpdatedRoute_routeGetsUpdated() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        String exerciseRecordId =
+                insertRecords(List.of(sessionWithRoute)).get(0).getMetadata().getId();
+        ExerciseSessionRecord sessionWithUpdatedRoute =
+                getExerciseSessionWithAnotherRoute(getMetadataForId(exerciseRecordId));
+
+        updateRecords(List.of(sessionWithUpdatedRoute));
+
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithUpdatedRoute.getRoute());
+    }
+
+    @Test
+    public void insertRecords_multipleSessions() throws Exception {
+        ExerciseSessionRecord sessionWithRoute =
+                getExerciseSession(
+                        getEmptyMetadata(), yesterdayAt("09:00"), getRoute(yesterdayAt("09:00")));
+        ExerciseSessionRecord sessionWithAnotherRoute =
+                getExerciseSession(
+                        getEmptyMetadata(),
+                        yesterdayAt("10:00"),
+                        getAnotherRoute(yesterdayAt("10:00")));
+        ExerciseSessionRecord sessionWithoutRoute =
+                getExerciseSessionWithoutRoute(getEmptyMetadata(), yesterdayAt("11:00"));
+
+        List<String> ids =
+                insertRecords(
+                                List.of(
+                                        sessionWithRoute,
+                                        sessionWithAnotherRoute,
+                                        sessionWithoutRoute))
+                        .stream()
+                        .map(r -> r.getMetadata().getId())
+                        .toList();
+
+        String sessionWithRouteId = ids.get(0);
+        String sessionWithAnotherRouteId = ids.get(1);
+        String sessionWithoutRouteId = ids.get(2);
+        List<ExerciseSessionRecord> records = readAllExerciseSessionRecordsPrivileged();
+        Map<String, ExerciseSessionRecord> idToRecord =
+                records.stream().collect(Collectors.toMap(r -> r.getMetadata().getId(), r -> r));
+        assertThat(idToRecord).hasSize(3);
+        assertThat(idToRecord.get(sessionWithRouteId).hasRoute()).isTrue();
+        assertThat(idToRecord.get(sessionWithRouteId).getRoute())
+                .isEqualTo(sessionWithRoute.getRoute());
+        assertThat(idToRecord.get(sessionWithAnotherRouteId).hasRoute()).isTrue();
+        assertThat(idToRecord.get(sessionWithAnotherRouteId).getRoute())
+                .isEqualTo(sessionWithAnotherRoute.getRoute());
+        assertThat(idToRecord.get(sessionWithoutRouteId).hasRoute()).isFalse();
+        assertThat(idToRecord.get(sessionWithoutRouteId).getRoute()).isNull();
+    }
+}
diff --git a/tests/cts/route/src/android/healthconnect/cts/route/ReadExerciseRoutePermissionTest.java b/tests/cts/route/src/android/healthconnect/cts/route/ReadExerciseRoutePermissionTest.java
new file mode 100644
index 0000000..b75024d
--- /dev/null
+++ b/tests/cts/route/src/android/healthconnect/cts/route/ReadExerciseRoutePermissionTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts.route;
+
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.ROUTE_WRITER_APP;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.assertCorrectHealthPermissions;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithRoute;
+import static android.healthconnect.cts.utils.DataFactory.getEmptyMetadata;
+import static android.healthconnect.cts.utils.PermissionHelper.READ_EXERCISE_ROUTE_PERMISSION;
+import static android.healthconnect.cts.utils.TestUtils.deleteAllStagedRemoteData;
+import static android.healthconnect.cts.utils.TestUtils.getChangeLogToken;
+import static android.healthconnect.cts.utils.TestUtils.getChangeLogs;
+import static android.healthconnect.cts.utils.TestUtils.readRecords;
+
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.ReadRecordsRequestUsingIds;
+import android.health.connect.changelog.ChangeLogTokenRequest;
+import android.health.connect.changelog.ChangeLogsRequest;
+import android.health.connect.changelog.ChangeLogsResponse;
+import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+
+public class ReadExerciseRoutePermissionTest {
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
+    @Before
+    public void setUp() throws Exception {
+        assertCorrectHealthPermissions();
+    }
+
+    @After
+    public void tearDown() throws InterruptedException {
+        deleteAllStagedRemoteData();
+    }
+
+    @Test
+    public void readRecords_usingFilters_canAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(sessionWithRoute);
+
+        List<ExerciseSessionRecord> records =
+                runWithShellPermissionIdentity(
+                        () ->
+                                readRecords(
+                                        new ReadRecordsRequestUsingFilters.Builder<>(
+                                                        ExerciseSessionRecord.class)
+                                                .build()),
+                        READ_EXERCISE_ROUTE_PERMISSION);
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingIds_canAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+
+        List<ExerciseSessionRecord> records =
+                runWithShellPermissionIdentity(
+                        () ->
+                                readRecords(
+                                        new ReadRecordsRequestUsingIds.Builder<>(
+                                                        ExerciseSessionRecord.class)
+                                                .addId(sessionId)
+                                                .build()),
+                        READ_EXERCISE_ROUTE_PERMISSION);
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(otherAppSession.getRoute());
+    }
+
+    @Test
+    public void getChangelogs_canAccessOtherAppRoute() throws Exception {
+        String token =
+                getChangeLogToken(
+                                new ChangeLogTokenRequest.Builder()
+                                        .addRecordType(ExerciseSessionRecord.class)
+                                        .build())
+                        .getToken();
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(otherAppSession);
+
+        ChangeLogsResponse response =
+                runWithShellPermissionIdentity(
+                        () -> getChangeLogs(new ChangeLogsRequest.Builder(token).build()),
+                        READ_EXERCISE_ROUTE_PERMISSION);
+
+        List<ExerciseSessionRecord> records =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .toList();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(otherAppSession.getRoute());
+    }
+}
diff --git a/tests/cts/route/src/android/healthconnect/cts/route/ReadExerciseRoutesPermissionTest.java b/tests/cts/route/src/android/healthconnect/cts/route/ReadExerciseRoutesPermissionTest.java
new file mode 100644
index 0000000..39db3fe
--- /dev/null
+++ b/tests/cts/route/src/android/healthconnect/cts/route/ReadExerciseRoutesPermissionTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts.route;
+
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.ROUTES_READER_WRITER_APP;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.ROUTE_WRITER_APP;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.assertCorrectHealthPermissions;
+import static android.healthconnect.cts.route.ExerciseRouteTestHelper.getExerciseSessionWithRoute;
+import static android.healthconnect.cts.utils.DataFactory.getEmptyMetadata;
+import static android.healthconnect.cts.utils.TestUtils.connectAppsWithGrantedPermissions;
+import static android.healthconnect.cts.utils.TestUtils.deleteAllStagedRemoteData;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.ReadRecordsRequestUsingIds;
+import android.health.connect.changelog.ChangeLogTokenRequest;
+import android.health.connect.changelog.ChangeLogsRequest;
+import android.health.connect.changelog.ChangeLogsResponse;
+import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class ReadExerciseRoutesPermissionTest {
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
+    @Before
+    public void setUp() throws Exception {
+        assertCorrectHealthPermissions();
+        connectAppsWithGrantedPermissions();
+    }
+
+    @After
+    public void tearDown() throws InterruptedException {
+        deleteAllStagedRemoteData();
+    }
+
+    @Test
+    public void readRecords_usingFilters_canAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(sessionWithRoute);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_APP.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingFilters_canAccessOwnRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTES_READER_WRITER_APP.insertRecords(List.of(sessionWithRoute));
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_APP.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingFilters_mixedOwnAndOtherAppSession() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String otherAppSessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+        ExerciseSessionRecord ownSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String ownSessionId = ROUTES_READER_WRITER_APP.insertRecords(ownSession).get(0);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_APP.readRecords(
+                        new ReadRecordsRequestUsingFilters.Builder<>(ExerciseSessionRecord.class)
+                                .build());
+
+        Map<String, ExerciseSessionRecord> idToRecordMap =
+                records.stream()
+                        .collect(
+                                Collectors.toMap(
+                                        record -> record.getMetadata().getId(),
+                                        Function.identity()));
+        assertThat(records).hasSize(2);
+        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(otherAppSessionId).getRoute())
+                .isEqualTo(otherAppSession.getRoute());
+        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingIds_canAccessOtherAppRoute() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_APP.readRecords(
+                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
+                                .addId(sessionId)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(otherAppSession.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingIds_canAccessOwnRoute() throws Exception {
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        String sessionId = ROUTES_READER_WRITER_APP.insertRecords(sessionWithRoute).get(0);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_APP.readRecords(
+                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
+                                .addId(sessionId)
+                                .build());
+
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void readRecords_usingIds_mixedOwnAndOtherAppSession() throws Exception {
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String otherAppSessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+        ExerciseSessionRecord ownSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String ownSessionId = ROUTES_READER_WRITER_APP.insertRecords(List.of(ownSession)).get(0);
+
+        List<ExerciseSessionRecord> records =
+                ROUTES_READER_WRITER_APP.readRecords(
+                        new ReadRecordsRequestUsingIds.Builder<>(ExerciseSessionRecord.class)
+                                .addId(otherAppSessionId)
+                                .addId(ownSessionId)
+                                .build());
+
+        Map<String, ExerciseSessionRecord> idToRecordMap =
+                records.stream()
+                        .collect(
+                                Collectors.toMap(
+                                        record -> record.getMetadata().getId(),
+                                        Function.identity()));
+        assertThat(records).hasSize(2);
+        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(otherAppSessionId).getRoute())
+                .isEqualTo(otherAppSession.getRoute());
+        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
+    }
+
+    @Test
+    public void getChangelogs_canAccessOtherAppRoute() throws Exception {
+        String token =
+                ROUTES_READER_WRITER_APP.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addRecordType(ExerciseSessionRecord.class)
+                                .build());
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTE_WRITER_APP.insertRecords(otherAppSession);
+
+        ChangeLogsResponse response =
+                ROUTES_READER_WRITER_APP.getChangeLogs(
+                        new ChangeLogsRequest.Builder(token).build());
+
+        List<ExerciseSessionRecord> records =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .toList();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(otherAppSession.getRoute());
+    }
+
+    @Test
+    public void getChangelogs_canAccessOwnRoute() throws Exception {
+        String token =
+                ROUTES_READER_WRITER_APP.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addRecordType(ExerciseSessionRecord.class)
+                                .build());
+        ExerciseSessionRecord sessionWithRoute = getExerciseSessionWithRoute(getEmptyMetadata());
+        ROUTES_READER_WRITER_APP.insertRecords(sessionWithRoute);
+
+        ChangeLogsResponse response =
+                ROUTES_READER_WRITER_APP.getChangeLogs(
+                        new ChangeLogsRequest.Builder(token).build());
+
+        List<ExerciseSessionRecord> records =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .toList();
+        assertThat(records).hasSize(1);
+        assertThat(records.get(0).hasRoute()).isTrue();
+        assertThat(records.get(0).getRoute()).isEqualTo(sessionWithRoute.getRoute());
+    }
+
+    @Test
+    public void getChangelogs_mixedOwnAndOtherAppSession() throws Exception {
+        String token =
+                ROUTES_READER_WRITER_APP.getChangeLogToken(
+                        new ChangeLogTokenRequest.Builder()
+                                .addRecordType(ExerciseSessionRecord.class)
+                                .build());
+        ExerciseSessionRecord otherAppSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String otherAppSessionId = ROUTE_WRITER_APP.insertRecords(otherAppSession).get(0);
+        ExerciseSessionRecord ownSession = getExerciseSessionWithRoute(getEmptyMetadata());
+        String ownSessionId = ROUTES_READER_WRITER_APP.insertRecords(List.of(ownSession)).get(0);
+
+        ChangeLogsResponse response =
+                ROUTES_READER_WRITER_APP.getChangeLogs(
+                        new ChangeLogsRequest.Builder(token).build());
+
+        Map<String, ExerciseSessionRecord> idToRecordMap =
+                response.getUpsertedRecords().stream()
+                        .map(ExerciseSessionRecord.class::cast)
+                        .collect(
+                                Collectors.toMap(
+                                        record -> record.getMetadata().getId(),
+                                        Function.identity()));
+        assertThat(response.getUpsertedRecords()).isNotNull();
+        assertThat(response.getUpsertedRecords()).hasSize(2);
+        assertThat(idToRecordMap.get(otherAppSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(otherAppSessionId).getRoute())
+                .isEqualTo(otherAppSession.getRoute());
+        assertThat(idToRecordMap.get(ownSessionId).hasRoute()).isTrue();
+        assertThat(idToRecordMap.get(ownSessionId).getRoute()).isEqualTo(ownSession.getRoute());
+    }
+}
diff --git a/tests/cts/src/android/healthconnect/cts/ExerciseRouteDisabledFeatureTest.java b/tests/cts/src/android/healthconnect/cts/ExerciseRouteDisabledFeatureTest.java
index 2c9045a..306810e 100644
--- a/tests/cts/src/android/healthconnect/cts/ExerciseRouteDisabledFeatureTest.java
+++ b/tests/cts/src/android/healthconnect/cts/ExerciseRouteDisabledFeatureTest.java
@@ -16,6 +16,8 @@
 
 package android.healthconnect.cts;
 
+import static android.healthconnect.cts.utils.DataFactory.buildExerciseSession;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.app.UiAutomation;
@@ -23,6 +25,7 @@
 import android.health.connect.ReadRecordsRequestUsingIds;
 import android.health.connect.datatypes.ExerciseSessionRecord;
 import android.health.connect.datatypes.Record;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.provider.DeviceConfig;
 
@@ -32,6 +35,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.util.List;
@@ -40,6 +44,11 @@
     private final UiAutomation mUiAutomation =
             InstrumentationRegistry.getInstrumentation().getUiAutomation();
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         setExerciseRouteFeatureEnabledFlag(true);
@@ -49,7 +58,7 @@
     public void testWriteRoute_insertWithDisableFeature_throwsException()
             throws InterruptedException {
         setExerciseRouteFeatureEnabledFlag(false);
-        List<Record> records = List.of(TestUtils.buildExerciseSession());
+        List<Record> records = List.of(buildExerciseSession());
         try {
             TestUtils.insertRecords(records);
             Assert.fail("Writing route when flag is disabled should not be allowed");
@@ -61,7 +70,7 @@
 
     @Test
     public void testReadRoute_insertAndRead_routeIsNotAvailable() throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildExerciseSession());
+        List<Record> records = List.of(buildExerciseSession());
         TestUtils.insertRecords(records);
         setExerciseRouteFeatureEnabledFlag(false);
         ExerciseSessionRecord insertedRecord = (ExerciseSessionRecord) records.get(0);
diff --git a/tests/cts/src/android/healthconnect/cts/GetActivityDatesTest.java b/tests/cts/src/android/healthconnect/cts/GetActivityDatesTest.java
index ff009ba..37b2cc6 100644
--- a/tests/cts/src/android/healthconnect/cts/GetActivityDatesTest.java
+++ b/tests/cts/src/android/healthconnect/cts/GetActivityDatesTest.java
@@ -28,12 +28,14 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.StepsRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -49,6 +51,11 @@
 public class GetActivityDatesTest {
     private static final String TAG = "GetActivityDatesTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/GetApplicationInfoTest.java b/tests/cts/src/android/healthconnect/cts/GetApplicationInfoTest.java
index 4e5a497..71a2dcd 100644
--- a/tests/cts/src/android/healthconnect/cts/GetApplicationInfoTest.java
+++ b/tests/cts/src/android/healthconnect/cts/GetApplicationInfoTest.java
@@ -16,7 +16,8 @@
 
 package android.healthconnect.cts;
 
-import static android.healthconnect.cts.utils.TestUtils.MANAGE_HEALTH_DATA;
+import static android.healthconnect.cts.utils.DataFactory.getTestRecords;
+import static android.healthconnect.cts.utils.PermissionHelper.MANAGE_HEALTH_DATA;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -26,6 +27,7 @@
 import android.health.connect.HealthConnectException;
 import android.health.connect.HealthConnectManager;
 import android.health.connect.datatypes.AppInfo;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.os.OutcomeReceiver;
 import android.platform.test.annotations.AppModeFull;
@@ -36,6 +38,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -52,6 +55,11 @@
     private static final UiAutomation sUiAutomation =
             InstrumentationRegistry.getInstrumentation().getUiAutomation();
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     /** TODO(b/257796081): Cleanup the database after each test. */
     @Test
     public void testEmptyApplicationInfo() throws InterruptedException {
@@ -108,7 +116,7 @@
     public void testGetApplicationInfo() throws InterruptedException {
         Context context = ApplicationProvider.getApplicationContext();
         CountDownLatch latch = new CountDownLatch(1);
-        TestUtils.insertRecords(TestUtils.getTestRecords());
+        TestUtils.insertRecords(getTestRecords());
         sUiAutomation.adoptShellPermissionIdentity(MANAGE_HEALTH_DATA);
 
         try {
diff --git a/tests/cts/src/android/healthconnect/cts/HealthConnectAccessLogsTest.java b/tests/cts/src/android/healthconnect/cts/HealthConnectAccessLogsTest.java
index d69d942..63786b6 100644
--- a/tests/cts/src/android/healthconnect/cts/HealthConnectAccessLogsTest.java
+++ b/tests/cts/src/android/healthconnect/cts/HealthConnectAccessLogsTest.java
@@ -16,6 +16,9 @@
 
 package android.healthconnect.cts;
 
+import static android.healthconnect.cts.utils.DataFactory.getStepsRecord;
+import static android.healthconnect.cts.utils.DataFactory.getTestRecords;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
@@ -28,6 +31,7 @@
 import android.health.connect.datatypes.HeartRateRecord;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.StepsRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -35,6 +39,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -45,6 +50,12 @@
 @AppModeFull(reason = "HealthConnectManager is not accessible to instant apps")
 @RunWith(AndroidJUnit4.class)
 public class HealthConnectAccessLogsTest {
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         Context context = ApplicationProvider.getApplicationContext();
@@ -59,7 +70,7 @@
     @Test
     public void testAccessLogs_read_singleRecordType() throws InterruptedException {
         List<AccessLog> oldAccessLogsResponse = TestUtils.queryAccessLogs();
-        List<Record> testRecord = Collections.singletonList(TestUtils.getStepsRecord());
+        List<Record> testRecord = Collections.singletonList(getStepsRecord());
         TestUtils.insertRecords(testRecord);
         TestUtils.readRecords(
                 new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class).build());
@@ -78,7 +89,7 @@
     @Test
     public void testAccessLogs_read_multipleRecordTypes() throws InterruptedException {
         List<AccessLog> oldAccessLogsResponse = TestUtils.queryAccessLogs();
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         TestUtils.readRecords(
                 new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class).build());
@@ -96,7 +107,7 @@
     @Test
     public void testAccessLogs_afterInsert() throws InterruptedException {
         List<AccessLog> oldAccessLogsResponse = TestUtils.queryAccessLogs();
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         // Wait for some time before fetching access logs as they are updated in the background.
         Thread.sleep(500);
diff --git a/tests/cts/src/android/healthconnect/cts/HealthConnectManagerTest.java b/tests/cts/src/android/healthconnect/cts/HealthConnectManagerTest.java
index 5538d10..c0a16d3 100644
--- a/tests/cts/src/android/healthconnect/cts/HealthConnectManagerTest.java
+++ b/tests/cts/src/android/healthconnect/cts/HealthConnectManagerTest.java
@@ -30,7 +30,8 @@
 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_HEART_RATE;
 import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_STEPS;
 import static android.health.connect.datatypes.StepsRecord.STEPS_COUNT_TOTAL;
-import static android.healthconnect.cts.utils.TestUtils.MANAGE_HEALTH_DATA;
+import static android.healthconnect.cts.utils.DataFactory.getRecordsAndIdentifiers;
+import static android.healthconnect.cts.utils.PermissionHelper.MANAGE_HEALTH_DATA;
 import static android.healthconnect.cts.utils.TestUtils.getRecordById;
 import static android.healthconnect.cts.utils.TestUtils.insertRecords;
 
@@ -38,8 +39,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assert.assertThrows;
-
 import static java.time.ZoneOffset.UTC;
 import static java.time.temporal.ChronoUnit.DAYS;
 import static java.time.temporal.ChronoUnit.HOURS;
@@ -58,10 +57,7 @@
 import android.health.connect.HealthDataCategory;
 import android.health.connect.HealthPermissions;
 import android.health.connect.LocalTimeRangeFilter;
-import android.health.connect.ReadRecordsRequest;
-import android.health.connect.ReadRecordsRequestUsingFilters;
 import android.health.connect.ReadRecordsRequestUsingIds;
-import android.health.connect.ReadRecordsResponse;
 import android.health.connect.RecordTypeInfoResponse;
 import android.health.connect.TimeInstantRangeFilter;
 import android.health.connect.changelog.ChangeLogTokenRequest;
@@ -80,6 +76,8 @@
 import android.health.connect.datatypes.units.Power;
 import android.health.connect.datatypes.units.Volume;
 import android.health.connect.restore.StageRemoteDataException;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.DataFactory;
 import android.healthconnect.cts.utils.TestUtils;
 import android.os.OutcomeReceiver;
 import android.os.ParcelFileDescriptor;
@@ -95,6 +93,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -126,6 +125,11 @@
     private static final String TAG = "HealthConnectManagerTest";
     private static final String APP_PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void before() throws InterruptedException {
         deleteAllRecords();
@@ -166,8 +170,7 @@
 
     @Test
     public void testRecordIdentifiers() {
-        for (TestUtils.RecordAndIdentifier recordAndIdentifier :
-                TestUtils.getRecordsAndIdentifiers()) {
+        for (TestUtils.RecordAndIdentifier recordAndIdentifier : getRecordsAndIdentifiers()) {
             assertThat(recordAndIdentifier.getRecordClass().getRecordType())
                     .isEqualTo(recordAndIdentifier.getId());
         }
@@ -194,7 +197,8 @@
     public void testRandomIdWithInsert() throws Exception {
         // Insert a sample record of each data type.
         List<Record> insertRecords =
-                TestUtils.insertRecords(Collections.singletonList(TestUtils.getStepsRecord("abc")));
+                TestUtils.insertRecords(
+                        Collections.singletonList(DataFactory.getStepsRecord("abc")));
         assertThat(insertRecords.get(0).getMetadata().getId()).isNotNull();
         assertThat(insertRecords.get(0).getMetadata().getId()).isNotEqualTo("abc");
     }
@@ -557,7 +561,7 @@
     }
 
     @Test
-    public void testInsertRecords_instantDifferentClientIdsAndSameTime_doesNotOwerwrite()
+    public void testInsertRecords_instantDifferentClientIdsAndSameTime_doesNotOverwrite()
             throws InterruptedException {
         final Power bmr1 = Power.fromWatts(100.0);
         final Power bmr2 = Power.fromWatts(110.0);
@@ -645,93 +649,6 @@
     }
 
     @Test
-    public void testReadRecords_readByIdMaxPageSizeExceeded_throws() {
-        int maxPageSize = 5000;
-        ReadRecordsRequestUsingIds.Builder<StepsRecord> request =
-                new ReadRecordsRequestUsingIds.Builder<>(StepsRecord.class);
-        for (int i = 0; i < maxPageSize; i++) {
-            request.addClientRecordId("client.id" + i);
-        }
-        Throwable thrown =
-                assertThrows(IllegalArgumentException.class, () -> request.addId("extra_id"));
-        assertThat(thrown.getMessage()).contains("Maximum allowed pageSize is 5000");
-        thrown =
-                assertThrows(
-                        IllegalArgumentException.class,
-                        () -> request.addClientRecordId("extra_client_id"));
-        assertThat(thrown.getMessage()).contains("Maximum allowed pageSize is 5000");
-    }
-
-    @Test
-    public void testReadRecords_readByFilterMaxPageSizeExceeded_throws() {
-        int maxPageSize = 5000;
-        ReadRecordsRequestUsingFilters.Builder<StepsRecord> request =
-                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class);
-        Throwable thrown =
-                assertThrows(
-                        IllegalArgumentException.class, () -> request.setPageSize(maxPageSize + 1));
-        assertThat(thrown.getMessage()).contains("Maximum allowed pageSize is 5000");
-    }
-
-    @Test
-    public void testReadRecords_multiplePagesSameStartTimeRecords_paginatedCorrectly()
-            throws Exception {
-        Instant startTime = Instant.now().minus(1, DAYS);
-
-        insertRecords(
-                List.of(
-                        getStepsRecord(
-                                "client.id1",
-                                "package.name",
-                                /* count= */ 100,
-                                startTime,
-                                startTime.plusSeconds(500)),
-                        getStepsRecord(
-                                "client.id2",
-                                "package.name",
-                                /* count= */ 100,
-                                startTime,
-                                startTime.plusSeconds(200)),
-                        getStepsRecord(
-                                "client.id3",
-                                "package.name",
-                                /* count= */ 100,
-                                startTime,
-                                startTime.plusSeconds(400)),
-                        getStepsRecord(
-                                "client.id4",
-                                "package.name",
-                                /* count= */ 100,
-                                startTime,
-                                startTime.plusSeconds(300))));
-
-        ReadRecordsRequest<StepsRecord> request1 =
-                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class)
-                        .setPageSize(2)
-                        .setAscending(false)
-                        .build();
-        ReadRecordsResponse<StepsRecord> result1 = TestUtils.readRecordsWithPagination(request1);
-        assertThat(result1.getRecords()).hasSize(2);
-        assertThat(result1.getRecords().get(0).getMetadata().getClientRecordId())
-                .isEqualTo("client.id1");
-        assertThat(result1.getRecords().get(1).getMetadata().getClientRecordId())
-                .isEqualTo("client.id2");
-
-        ReadRecordsRequest<StepsRecord> request2 =
-                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class)
-                        .setPageSize(2)
-                        .setPageToken(result1.getNextPageToken())
-                        .build();
-        ReadRecordsResponse<StepsRecord> result2 = TestUtils.readRecordsWithPagination(request2);
-        assertThat(result2.getRecords()).hasSize(2);
-        assertThat(result2.getRecords().get(0).getMetadata().getClientRecordId())
-                .isEqualTo("client.id3");
-        assertThat(result2.getRecords().get(1).getMetadata().getClientRecordId())
-                .isEqualTo("client.id4");
-        assertThat(result2.getNextPageToken()).isEqualTo(-1);
-    }
-
-    @Test
     public void testAggregation_stepsCountTotal_acrossDST_works() throws Exception {
         ZoneOffset utcPlusOne = ZoneOffset.ofTotalSeconds(UTC.getTotalSeconds() + 3600);
 
@@ -1629,7 +1546,7 @@
                 },
                 Manifest.permission.MIGRATE_HEALTH_CONNECT_DATA);
 
-        StepsRecord testRecord = TestUtils.getStepsRecord();
+        StepsRecord testRecord = DataFactory.getStepsRecord();
 
         try {
             TestUtils.insertRecords(Collections.singletonList(testRecord));
@@ -1788,7 +1705,7 @@
     public void testGetRecordTypeInfo_InsertRecords_correctContributingPackages() throws Exception {
         // Insert a set of test records for StepRecords, ExerciseSessionRecord, HeartRateRecord,
         // BasalMetabolicRateRecord.
-        List<Record> testRecords = TestUtils.getTestRecords();
+        List<Record> testRecords = DataFactory.getTestRecords();
         TestUtils.insertRecords(testRecords);
 
         // Populate expected records. This method puts empty lists as contributing packages for all
@@ -1849,7 +1766,7 @@
             throws Exception {
         // Insert a sets of test records for StepRecords, ExerciseSessionRecord, HeartRateRecord,
         // BasalMetabolicRateRecord.
-        List<Record> testRecords = TestUtils.getTestRecords();
+        List<Record> testRecords = DataFactory.getTestRecords();
         TestUtils.insertRecords(testRecords);
 
         // Populate expected records. This method puts empty lists as contributing packages for all
@@ -1914,10 +1831,10 @@
             throws Exception {
         // Insert 2 sets of test records for StepRecords, ExerciseSessionRecord, HeartRateRecord,
         // BasalMetabolicRateRecord.
-        List<Record> testRecords = TestUtils.getTestRecords();
+        List<Record> testRecords = DataFactory.getTestRecords();
         TestUtils.insertRecords(testRecords);
 
-        List<Record> testRecords2 = TestUtils.getTestRecords();
+        List<Record> testRecords2 = DataFactory.getTestRecords();
         TestUtils.insertRecords(testRecords2);
 
         // When recordTypes are modified the appInfo also gets updated and this update happens on
diff --git a/tests/cts/src/android/healthconnect/cts/HealthPermissionCategoryPriorityTests.java b/tests/cts/src/android/healthconnect/cts/HealthPermissionCategoryPriorityTests.java
index ac1a3b2..e29f1d8 100644
--- a/tests/cts/src/android/healthconnect/cts/HealthPermissionCategoryPriorityTests.java
+++ b/tests/cts/src/android/healthconnect/cts/HealthPermissionCategoryPriorityTests.java
@@ -22,7 +22,7 @@
 import static android.health.connect.HealthDataCategory.NUTRITION;
 import static android.health.connect.HealthDataCategory.SLEEP;
 import static android.health.connect.HealthDataCategory.VITALS;
-import static android.healthconnect.cts.utils.TestUtils.MANAGE_HEALTH_DATA;
+import static android.healthconnect.cts.utils.PermissionHelper.MANAGE_HEALTH_DATA;
 import static android.healthconnect.cts.utils.TestUtils.getPriority;
 import static android.healthconnect.cts.utils.TestUtils.getPriorityWithManageHealthDataPermission;
 import static android.healthconnect.cts.utils.TestUtils.updatePriority;
@@ -33,6 +33,7 @@
 import android.app.UiAutomation;
 import android.health.connect.FetchDataOriginsPriorityOrderResponse;
 import android.health.connect.HealthConnectException;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.InstrumentationRegistry;
@@ -41,6 +42,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,6 +61,11 @@
     public static final String PACKAGE_NAME = "android.healthconnect.cts";
     public static final String OTHER_PACKAGE_NAME = "";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/HealthServicesInitializerTest.java b/tests/cts/src/android/healthconnect/cts/HealthServicesInitializerTest.java
new file mode 100644
index 0000000..f2fbd17
--- /dev/null
+++ b/tests/cts/src/android/healthconnect/cts/HealthServicesInitializerTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts;
+
+import static android.healthconnect.cts.utils.TestUtils.isHardwareSupported;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.content.Context;
+import android.health.connect.HealthServicesInitializer;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+
+public class HealthServicesInitializerTest {
+    /**
+     * HealthServicesInitializer.registerServiceWrappers() should only be called by
+     * SystemServiceRegistry during boot up. Calling this API at any other time should throw an
+     * exception.
+     */
+    @Test
+    public void testRegisterServiceThrowsException() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        // skip the test if the hardware not supported
+        if (!isHardwareSupported(context)) {
+            return;
+        }
+        assertThrows(
+                IllegalStateException.class, HealthServicesInitializer::registerServiceWrappers);
+    }
+
+    /**
+     * context.getSystemService(Context.HEALTHCONNECT_SERVICE) returns the services on supported
+     * devices.
+     */
+    @Test
+    public void testHealthServiceRegistered() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        Object service = context.getSystemService(Context.HEALTHCONNECT_SERVICE);
+        if (isHardwareSupported(context)) {
+            assertThat(service).isNotNull();
+        } else {
+            assertThat(service).isNull();
+        }
+    }
+}
diff --git a/tests/cts/src/android/healthconnect/cts/HistoricAccessLimitTest.java b/tests/cts/src/android/healthconnect/cts/HistoricAccessLimitTest.java
index 86c17d4..bf3be93 100644
--- a/tests/cts/src/android/healthconnect/cts/HistoricAccessLimitTest.java
+++ b/tests/cts/src/android/healthconnect/cts/HistoricAccessLimitTest.java
@@ -27,6 +27,7 @@
 import android.health.connect.datatypes.StepsRecord;
 import android.health.connect.datatypes.WeightRecord;
 import android.health.connect.datatypes.units.Mass;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestReceiver;
 import android.healthconnect.cts.utils.TestUtils;
 import android.os.Bundle;
@@ -37,6 +38,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -53,6 +55,11 @@
 
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
@@ -258,13 +265,7 @@
     }
 
     private String insertStepsRecordViaTestApp(Instant startTime, Instant endTime, long value) {
-        Bundle bundle = new Bundle();
-        bundle.putLongArray(EXTRA_TIMES, new long[] {startTime.toEpochMilli()});
-        bundle.putLongArray(EXTRA_END_TIMES, new long[] {endTime.toEpochMilli()});
-        bundle.putLongArray(EXTRA_RECORD_VALUES, new long[] {value});
-        TestReceiver.reset();
-        sendCommandToTestAppReceiver(mContext, ACTION_INSERT_STEPS_RECORDS, bundle);
-        return TestReceiver.getResult().getStringArrayList(EXTRA_RECORD_IDS).get(0);
+        return TestUtils.insertStepsRecordViaTestApp(mContext, startTime, endTime, value).get(0);
     }
 
     private String insertWeightRecordViaTestApp(Instant startTime, long value) {
diff --git a/tests/cts/src/android/healthconnect/cts/SessionDatatypeDisabledFeatureTest.java b/tests/cts/src/android/healthconnect/cts/SessionDatatypeDisabledFeatureTest.java
index cfe1f15..340fc4c 100644
--- a/tests/cts/src/android/healthconnect/cts/SessionDatatypeDisabledFeatureTest.java
+++ b/tests/cts/src/android/healthconnect/cts/SessionDatatypeDisabledFeatureTest.java
@@ -16,6 +16,9 @@
 
 package android.healthconnect.cts;
 
+import static android.healthconnect.cts.utils.DataFactory.buildExerciseSession;
+import static android.healthconnect.cts.utils.DataFactory.buildSleepSession;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.app.UiAutomation;
@@ -25,6 +28,7 @@
 import android.health.connect.datatypes.ExerciseSessionRecord;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.SleepSessionRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.provider.DeviceConfig;
 
@@ -34,6 +38,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.time.Instant;
@@ -49,6 +54,11 @@
                     .setEndTime(Instant.now())
                     .build();
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         setSessionDatatypesFeatureEnabledFlag(true);
@@ -60,7 +70,7 @@
     public void testWriteExerciseSession_insertWithDisableFeature_throwsException()
             throws InterruptedException {
         setSessionDatatypesFeatureEnabledFlag(false);
-        List<Record> records = List.of(TestUtils.buildExerciseSession());
+        List<Record> records = List.of(buildExerciseSession());
         try {
             TestUtils.insertRecords(records);
             Assert.fail("Writing exercise session when flag is disabled should not be allowed");
@@ -73,7 +83,7 @@
     @Test
     public void testReadExerciseSession_insertAndRead_sessionIsNotAvailable()
             throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildExerciseSession());
+        List<Record> records = List.of(buildExerciseSession());
         TestUtils.insertRecords(records);
         setSessionDatatypesFeatureEnabledFlag(false);
         ReadRecordsRequestUsingIds.Builder<ExerciseSessionRecord> request =
@@ -87,7 +97,7 @@
     public void testWriteSleepSession_insertWithDisableFeature_throwsException()
             throws InterruptedException {
         setSessionDatatypesFeatureEnabledFlag(false);
-        List<Record> records = List.of(TestUtils.buildSleepSession());
+        List<Record> records = List.of(buildSleepSession());
         try {
             TestUtils.insertRecords(records);
             Assert.fail("Writing sleep session when flag is disabled should not be allowed");
@@ -100,7 +110,7 @@
     @Test
     public void testReadSleepSession_insertAndRead_sessionIsNotAvailable()
             throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildSleepSession());
+        List<Record> records = List.of(buildSleepSession());
         TestUtils.insertRecords(records);
         setSessionDatatypesFeatureEnabledFlag(false);
 
diff --git a/tests/cts/src/android/healthconnect/cts/SharedMemoryTest.java b/tests/cts/src/android/healthconnect/cts/SharedMemoryTest.java
index 60d5458..6aa64a9 100644
--- a/tests/cts/src/android/healthconnect/cts/SharedMemoryTest.java
+++ b/tests/cts/src/android/healthconnect/cts/SharedMemoryTest.java
@@ -42,12 +42,14 @@
 import android.health.connect.datatypes.WeightRecord;
 import android.health.connect.datatypes.units.Length;
 import android.health.connect.datatypes.units.Mass;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -61,6 +63,11 @@
 @RunWith(AndroidJUnit4.class)
 public class SharedMemoryTest {
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void before() {
         deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/ExerciseDurationAggregationTest.java b/tests/cts/src/android/healthconnect/cts/aggregation/ExerciseDurationAggregationTest.java
similarity index 93%
rename from tests/cts/src/android/healthconnect/cts/ExerciseDurationAggregationTest.java
rename to tests/cts/src/android/healthconnect/cts/aggregation/ExerciseDurationAggregationTest.java
index 016a1c2..455e523 100644
--- a/tests/cts/src/android/healthconnect/cts/ExerciseDurationAggregationTest.java
+++ b/tests/cts/src/android/healthconnect/cts/aggregation/ExerciseDurationAggregationTest.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.aggregation;
 
 import static android.health.connect.datatypes.ExerciseSessionRecord.EXERCISE_DURATION_TOTAL;
-import static android.healthconnect.cts.utils.TestUtils.SESSION_END_TIME;
-import static android.healthconnect.cts.utils.TestUtils.SESSION_START_TIME;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_END_TIME;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_START_TIME;
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -32,10 +33,12 @@
 import android.health.connect.datatypes.ExerciseSegmentType;
 import android.health.connect.datatypes.ExerciseSessionRecord;
 import android.health.connect.datatypes.ExerciseSessionType;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.time.Duration;
@@ -70,6 +73,11 @@
 
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
@@ -90,7 +98,7 @@
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.ACTIVITY);
         ExerciseSessionRecord session =
                 new ExerciseSessionRecord.Builder(
-                                TestUtils.generateMetadata(),
+                                generateMetadata(),
                                 SESSION_START_TIME,
                                 SESSION_END_TIME,
                                 ExerciseSessionType
@@ -112,10 +120,9 @@
     public void testSimpleAggregation_oneSessionStartEarlierThanWindow_returnsOverlapDuration()
             throws InterruptedException {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.ACTIVITY);
-
         ExerciseSessionRecord session =
                 new ExerciseSessionRecord.Builder(
-                                TestUtils.generateMetadata(),
+                                generateMetadata(),
                                 SESSION_START_TIME.minusSeconds(10),
                                 SESSION_END_TIME,
                                 ExerciseSessionType
@@ -138,7 +145,7 @@
 
         ExerciseSessionRecord session =
                 new ExerciseSessionRecord.Builder(
-                                TestUtils.generateMetadata(),
+                                generateMetadata(),
                                 SESSION_START_TIME.minusSeconds(100),
                                 SESSION_END_TIME.plusSeconds(100),
                                 ExerciseSessionType
@@ -167,7 +174,7 @@
                         .build();
         ExerciseSessionRecord session =
                 new ExerciseSessionRecord.Builder(
-                                TestUtils.generateMetadata(),
+                                generateMetadata(),
                                 SESSION_START_TIME,
                                 SESSION_END_TIME,
                                 ExerciseSessionType.EXERCISE_SESSION_TYPE_CALISTHENICS)
@@ -200,11 +207,10 @@
     public void testAggregationByDuration_oneSession_returnsSplitDurationIntoGroups()
             throws InterruptedException {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.ACTIVITY);
-
         Instant endTime = SESSION_START_TIME.plus(10, ChronoUnit.HOURS);
         ExerciseSessionRecord session =
                 new ExerciseSessionRecord.Builder(
-                                TestUtils.generateMetadata(),
+                                generateMetadata(),
                                 SESSION_START_TIME,
                                 endTime,
                                 ExerciseSessionType.EXERCISE_SESSION_TYPE_BADMINTON)
@@ -233,14 +239,13 @@
     public void testAggregation_oneSessionLocalTimeFilter_findsSessionWithMinOffset()
             throws InterruptedException {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.ACTIVITY);
-
         Instant endTime = Instant.now();
         LocalDateTime endTimeLocal = LocalDateTime.ofInstant(endTime, ZoneOffset.UTC);
 
         long sessionDurationSeconds = 3600;
         ExerciseSessionRecord session =
                 new ExerciseSessionRecord.Builder(
-                                TestUtils.generateMetadata(),
+                                generateMetadata(),
                                 endTime.minusSeconds(sessionDurationSeconds),
                                 endTime,
                                 ExerciseSessionType.EXERCISE_SESSION_TYPE_BADMINTON)
@@ -266,11 +271,10 @@
     public void testAggregation_oneSessionLocalTimeFilterExcludeSegment_substractsExcludeInterval()
             throws InterruptedException {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.ACTIVITY);
-
         Instant endTime = SESSION_START_TIME.plus(1, ChronoUnit.HOURS);
         ExerciseSessionRecord session =
                 new ExerciseSessionRecord.Builder(
-                                TestUtils.generateMetadata(),
+                                generateMetadata(),
                                 SESSION_START_TIME,
                                 endTime,
                                 ExerciseSessionType.EXERCISE_SESSION_TYPE_BADMINTON)
diff --git a/tests/cts/src/android/healthconnect/cts/SleepDurationAggregationTest.java b/tests/cts/src/android/healthconnect/cts/aggregation/SleepDurationAggregationTest.java
similarity index 89%
rename from tests/cts/src/android/healthconnect/cts/SleepDurationAggregationTest.java
rename to tests/cts/src/android/healthconnect/cts/aggregation/SleepDurationAggregationTest.java
index c7b0b5f..3f5e5c5 100644
--- a/tests/cts/src/android/healthconnect/cts/SleepDurationAggregationTest.java
+++ b/tests/cts/src/android/healthconnect/cts/aggregation/SleepDurationAggregationTest.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.aggregation;
 
 import static android.health.connect.datatypes.SleepSessionRecord.SLEEP_DURATION_TOTAL;
-import static android.healthconnect.cts.utils.TestUtils.SESSION_END_TIME;
-import static android.healthconnect.cts.utils.TestUtils.SESSION_START_TIME;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_END_TIME;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_START_TIME;
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -28,10 +29,12 @@
 import android.health.connect.HealthDataCategory;
 import android.health.connect.TimeInstantRangeFilter;
 import android.health.connect.datatypes.SleepSessionRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.time.Duration;
@@ -54,6 +57,11 @@
 
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
@@ -74,7 +82,7 @@
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.SLEEP);
         SleepSessionRecord session =
                 new SleepSessionRecord.Builder(
-                                TestUtils.generateMetadata(), SESSION_START_TIME, SESSION_END_TIME)
+                                generateMetadata(), SESSION_START_TIME, SESSION_END_TIME)
                         .build();
         AggregateRecordsResponse<Long> response =
                 TestUtils.getAggregateResponse(mAggregateAllRecordsRequest, List.of(session));
@@ -92,7 +100,6 @@
     public void testSimpleAggregation_oneSessionWithAwake_returnsDurationMinusAwake()
             throws InterruptedException {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.SLEEP);
-
         SleepSessionRecord.Stage awakeStage =
                 new SleepSessionRecord.Stage(
                         SESSION_START_TIME,
@@ -100,7 +107,7 @@
                         SleepSessionRecord.StageType.STAGE_TYPE_AWAKE);
         SleepSessionRecord session =
                 new SleepSessionRecord.Builder(
-                                TestUtils.generateMetadata(), SESSION_START_TIME, SESSION_END_TIME)
+                                generateMetadata(), SESSION_START_TIME, SESSION_END_TIME)
                         .setStages(
                                 List.of(
                                         awakeStage,
@@ -139,11 +146,9 @@
     public void testAggregationByDuration_oneSession_returnsSplitDurationIntoGroups()
             throws InterruptedException {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.SLEEP);
-
         Instant endTime = SESSION_START_TIME.plus(10, ChronoUnit.HOURS);
         SleepSessionRecord session =
-                new SleepSessionRecord.Builder(
-                                TestUtils.generateMetadata(), SESSION_START_TIME, endTime)
+                new SleepSessionRecord.Builder(generateMetadata(), SESSION_START_TIME, endTime)
                         .build();
         TestUtils.insertRecords(List.of(session));
 
diff --git a/tests/cts/src/android/healthconnect/cts/HealthConnectChangeLogsTests.java b/tests/cts/src/android/healthconnect/cts/changelogs/HealthConnectChangeLogsTests.java
similarity index 90%
rename from tests/cts/src/android/healthconnect/cts/HealthConnectChangeLogsTests.java
rename to tests/cts/src/android/healthconnect/cts/changelogs/HealthConnectChangeLogsTests.java
index 33a3187..e896b37 100644
--- a/tests/cts/src/android/healthconnect/cts/HealthConnectChangeLogsTests.java
+++ b/tests/cts/src/android/healthconnect/cts/changelogs/HealthConnectChangeLogsTests.java
@@ -14,7 +14,11 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.changelogs;
+
+import static android.healthconnect.cts.utils.DataFactory.getHeartRateRecord;
+import static android.healthconnect.cts.utils.DataFactory.getStepsRecord;
+import static android.healthconnect.cts.utils.DataFactory.getTestRecords;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -25,8 +29,10 @@
 import android.health.connect.changelog.ChangeLogsRequest;
 import android.health.connect.changelog.ChangeLogsResponse;
 import android.health.connect.datatypes.DataOrigin;
+import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.StepsRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -34,11 +40,12 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
-import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.time.Instant;
+import java.time.temporal.ChronoUnit;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -48,6 +55,11 @@
 @RunWith(AndroidJUnit4.class)
 public class HealthConnectChangeLogsTests {
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         Context context = ApplicationProvider.getApplicationContext();
@@ -79,7 +91,7 @@
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
         assertThat(response.getDeletedLogs().size()).isEqualTo(0);
 
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(testRecord.size());
@@ -102,7 +114,7 @@
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
         assertThat(response.getDeletedLogs().size()).isEqualTo(0);
 
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
@@ -128,7 +140,7 @@
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
         assertThat(response.getDeletedLogs().size()).isEqualTo(0);
 
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(testRecord.size());
@@ -153,12 +165,12 @@
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
         assertThat(response.getDeletedLogs().size()).isEqualTo(0);
 
-        List<Record> testRecord = Collections.singletonList(TestUtils.getStepsRecord());
+        List<Record> testRecord = Collections.singletonList(getStepsRecord());
         TestUtils.insertRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(1);
         assertThat(response.getDeletedLogs().size()).isEqualTo(0);
-        testRecord = Collections.singletonList(TestUtils.getHeartRateRecord());
+        testRecord = Collections.singletonList(getHeartRateRecord());
         TestUtils.insertRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(1);
@@ -174,7 +186,7 @@
         ChangeLogsResponse response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
 
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         TestUtils.deleteRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
@@ -202,9 +214,9 @@
 
         List<Record> testRecord =
                 Arrays.asList(
-                        StepsRecordTest.getStepsRecord_minusDays(45),
-                        StepsRecordTest.getStepsRecord_minusDays(20),
-                        StepsRecordTest.getStepsRecord_minusDays(5));
+                        getStepsRecord_minusDays(45),
+                        getStepsRecord_minusDays(20),
+                        getStepsRecord_minusDays(5));
         TestUtils.insertRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(2);
@@ -231,7 +243,7 @@
         ChangeLogsResponse response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
 
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         TestUtils.deleteRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
@@ -258,7 +270,7 @@
         ChangeLogsResponse response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
 
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         TestUtils.deleteRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
@@ -286,13 +298,13 @@
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
         assertThat(response.getDeletedLogs().size()).isEqualTo(0);
 
-        List<Record> testRecord = Collections.singletonList(TestUtils.getStepsRecord());
+        List<Record> testRecord = Collections.singletonList(getStepsRecord());
         TestUtils.insertRecords(testRecord);
         TestUtils.deleteRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
         assertThat(response.getDeletedLogs().size()).isEqualTo(1);
-        testRecord = Collections.singletonList(TestUtils.getHeartRateRecord());
+        testRecord = Collections.singletonList(getHeartRateRecord());
         TestUtils.insertRecords(testRecord);
         TestUtils.deleteRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
@@ -309,7 +321,7 @@
         ChangeLogsResponse response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
 
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(1);
@@ -325,7 +337,7 @@
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
         assertThat(response.hasMorePages()).isFalse();
 
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.hasMorePages()).isTrue();
@@ -354,7 +366,7 @@
         ChangeLogsResponse response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
         assertThat(response.hasMorePages()).isFalse();
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         ChangeLogsResponse newResponse = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(newResponse.getUpsertedRecords().size()).isEqualTo(testRecord.size());
@@ -372,7 +384,7 @@
         ChangeLogsResponse response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
         assertThat(response.hasMorePages()).isFalse();
-        List<Record> testRecord = TestUtils.getTestRecords();
+        List<Record> testRecord = getTestRecords();
         TestUtils.insertRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(testRecord.size());
@@ -386,4 +398,13 @@
         assertThat(newResponse.hasMorePages()).isFalse();
         assertThat(newResponse.getNextChangesToken()).isEqualTo(changeLogsRequestNew.getToken());
     }
+
+    private static StepsRecord getStepsRecord_minusDays(int days) {
+        return new StepsRecord.Builder(
+                        new Metadata.Builder().build(),
+                        Instant.now().minus(days, ChronoUnit.DAYS),
+                        Instant.now().minus(days, ChronoUnit.DAYS).plusMillis(1000),
+                        10)
+                .build();
+    }
 }
diff --git a/tests/cts/src/android/healthconnect/cts/ActiveCaloriesBurnedRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/ActiveCaloriesBurnedRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/ActiveCaloriesBurnedRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/ActiveCaloriesBurnedRecordTest.java
index eecd084..55c4445 100644
--- a/tests/cts/src/android/healthconnect/cts/ActiveCaloriesBurnedRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/ActiveCaloriesBurnedRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.ActiveCaloriesBurnedRecord.ACTIVE_CALORIES_TOTAL;
 
@@ -40,6 +40,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Energy;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -49,6 +50,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -68,6 +70,11 @@
     private static final String TAG = "ActiveCaloriesBurnedRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/BasalBodyTemperatureRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/BasalBodyTemperatureRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/BasalBodyTemperatureRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/BasalBodyTemperatureRecordTest.java
index 2aefe73..3be97ad 100644
--- a/tests/cts/src/android/healthconnect/cts/BasalBodyTemperatureRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/BasalBodyTemperatureRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -35,6 +35,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Temperature;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -43,6 +44,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,6 +61,11 @@
 public class BasalBodyTemperatureRecordTest {
     private static final String TAG = "BasalBodyTemperatureRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/BasalMetabolicRateRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/BasalMetabolicRateRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/BasalMetabolicRateRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/BasalMetabolicRateRecordTest.java
index eb97dc2..173efc3 100644
--- a/tests/cts/src/android/healthconnect/cts/BasalMetabolicRateRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/BasalMetabolicRateRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.BasalMetabolicRateRecord.BASAL_CALORIES_TOTAL;
 
@@ -43,6 +43,7 @@
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Energy;
 import android.health.connect.datatypes.units.Power;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -52,6 +53,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -73,6 +75,11 @@
     private static final String TAG = "BasalMetabolicRateRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
@@ -446,7 +453,6 @@
     public void testAggregation_BasalCaloriesBurntTotal_groupByDuration_lbmDerived()
             throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         Instant now = Instant.now();
         List<Record> records =
                 List.of(
@@ -483,7 +489,6 @@
     @Test
     public void testAggregation_BasalCaloriesBurntTotal_profile_group() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         Instant now = Instant.now();
         List<Record> records =
                 List.of(
@@ -743,7 +748,6 @@
     public void testAggregation_BasalCaloriesBurntTotal_groupByDuration_profileDerived()
             throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         Instant now = Instant.now();
         List<Record> records =
                 List.of(
@@ -781,7 +785,6 @@
     @Test
     public void testAggregation_BasalCaloriesBurntTotal() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         List<Record> records =
                 Arrays.asList(
                         getBasalMetabolicRateRecord(30.0, Instant.now().minus(3, ChronoUnit.DAYS)),
@@ -831,7 +834,6 @@
     @Test
     public void testAggregation_BasalCaloriesBurntTotal_groupDuration() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         Instant now = Instant.now();
         List<Record> records =
                 List.of(
@@ -878,7 +880,6 @@
     public void testAggregation_BasalCaloriesBurntTotal_groupDurationLocalFilter()
             throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         Instant now = Instant.now();
         ZoneOffset offset = ZoneOffset.MIN;
         LocalDateTime nowLocal = LocalDateTime.ofInstant(now, offset);
@@ -920,7 +921,6 @@
     @Test
     public void testAggregation_BasalCaloriesBurntTotal_group() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         Instant now = Instant.now();
         List<Record> records =
                 List.of(
@@ -954,7 +954,6 @@
     @Test
     public void testAggregation_BasalCaloriesBurntTotal_profile() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         List<Record> records =
                 List.of(
                         HeightRecordTest.getBaseHeightRecord(
@@ -1188,6 +1187,7 @@
 
     @Test
     public void testAggregate_withDifferentTimeZone() throws Exception {
+        TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
         Instant instant = Instant.now().minus(1, ChronoUnit.DAYS);
         List<Record> records =
                 List.of(
@@ -1226,7 +1226,7 @@
                 .isEqualTo(ZoneOffset.ofHours(5));
     }
 
-    BasalMetabolicRateRecord getBasalMetabolicRateRecord_update(
+    private static BasalMetabolicRateRecord getBasalMetabolicRateRecord_update(
             Record record, String id, String clientRecordId) {
         Metadata metadata = record.getMetadata();
         Metadata metadataWithId =
@@ -1244,7 +1244,7 @@
                 .build();
     }
 
-    static BasalMetabolicRateRecord getBaseBasalMetabolicRateRecord() {
+    private static BasalMetabolicRateRecord getBaseBasalMetabolicRateRecord() {
         return new BasalMetabolicRateRecord.Builder(
                         new Metadata.Builder().setDataOrigin(getDataOrigin()).build(),
                         Instant.now().minus(1, ChronoUnit.DAYS),
diff --git a/tests/cts/src/android/healthconnect/cts/BloodGlucoseRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/BloodGlucoseRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/BloodGlucoseRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/BloodGlucoseRecordTest.java
index d4e58e0..170620b 100644
--- a/tests/cts/src/android/healthconnect/cts/BloodGlucoseRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/BloodGlucoseRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -35,6 +35,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.BloodGlucose;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -43,6 +44,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,6 +61,11 @@
 public class BloodGlucoseRecordTest {
     private static final String TAG = "BloodGlucoseRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/BloodPressureRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/BloodPressureRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/BloodPressureRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/BloodPressureRecordTest.java
index 72420cc..a159cf9 100644
--- a/tests/cts/src/android/healthconnect/cts/BloodPressureRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/BloodPressureRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.BloodPressureRecord.DIASTOLIC_AVG;
 import static android.health.connect.datatypes.BloodPressureRecord.DIASTOLIC_MAX;
@@ -45,6 +45,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Pressure;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -54,6 +55,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -73,6 +75,11 @@
     private static final String TAG = "BloodPressureRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/BodyFatRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/BodyFatRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/BodyFatRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/BodyFatRecordTest.java
index 978f13c..c1feaa1 100644
--- a/tests/cts/src/android/healthconnect/cts/BodyFatRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/BodyFatRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -35,6 +35,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Percentage;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -43,6 +44,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,6 +61,11 @@
 public class BodyFatRecordTest {
     private static final String TAG = "BodyFatRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/BodyTemperatureRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/BodyTemperatureRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/BodyTemperatureRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/BodyTemperatureRecordTest.java
index 5089e97..5965357 100644
--- a/tests/cts/src/android/healthconnect/cts/BodyTemperatureRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/BodyTemperatureRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -35,6 +35,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Temperature;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -43,6 +44,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,6 +61,11 @@
 public class BodyTemperatureRecordTest {
     private static final String TAG = "BodyTemperatureRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/BodyWaterMassRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/BodyWaterMassRecordTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/BodyWaterMassRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/BodyWaterMassRecordTest.java
index 12d3a6e..2c0ac51 100644
--- a/tests/cts/src/android/healthconnect/cts/BodyWaterMassRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/BodyWaterMassRecordTest.java
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
+
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -35,6 +37,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Mass;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -43,6 +46,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -60,6 +64,11 @@
     private static final String TAG = "BodyWaterMassRecordTest";
     private static final Instant TIME = Instant.ofEpochMilli((long) 1e9);
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
@@ -303,15 +312,14 @@
     @Test
     public void testBodyWaterMass_buildSession_buildCorrectObject() {
         BodyWaterMassRecord record =
-                new BodyWaterMassRecord.Builder(
-                                TestUtils.generateMetadata(), TIME, Mass.fromGrams(40))
+                new BodyWaterMassRecord.Builder(generateMetadata(), TIME, Mass.fromGrams(40))
                         .build();
         assertThat(record.getTime()).isEqualTo(TIME);
     }
 
     @Test
     public void testBodyWaterMass_buildEqualSessions_equalsReturnsTrue() {
-        Metadata metadata = TestUtils.generateMetadata();
+        Metadata metadata = generateMetadata();
         BodyWaterMassRecord record =
                 new BodyWaterMassRecord.Builder(metadata, TIME, Mass.fromGrams(40)).build();
         BodyWaterMassRecord record2 =
@@ -322,8 +330,7 @@
     @Test
     public void testBodyWaterMass_buildSessionWithAllFields_buildCorrectObject() {
         BodyWaterMassRecord record =
-                new BodyWaterMassRecord.Builder(
-                                TestUtils.generateMetadata(), TIME, Mass.fromGrams(40))
+                new BodyWaterMassRecord.Builder(generateMetadata(), TIME, Mass.fromGrams(40))
                         .setZoneOffset(ZoneOffset.MAX)
                         .build();
         assertThat(record.getZoneOffset()).isEqualTo(ZoneOffset.MAX);
diff --git a/tests/cts/src/android/healthconnect/cts/BoneMassRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/BoneMassRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/BoneMassRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/BoneMassRecordTest.java
index 50d9e47..a4635af 100644
--- a/tests/cts/src/android/healthconnect/cts/BoneMassRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/BoneMassRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -35,6 +35,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Mass;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -43,6 +44,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,6 +61,11 @@
 public class BoneMassRecordTest {
     private static final String TAG = "BoneMassRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/CervicalMucusRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/CervicalMucusRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/CervicalMucusRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/CervicalMucusRecordTest.java
index 408a6e8..1307a17 100644
--- a/tests/cts/src/android/healthconnect/cts/CervicalMucusRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/CervicalMucusRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -34,6 +34,7 @@
 import android.health.connect.datatypes.Device;
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -42,6 +43,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -58,6 +60,11 @@
 public class CervicalMucusRecordTest {
     private static final String TAG = "CervicalMucusRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/CyclingPedalingCadenceRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/CyclingPedalingCadenceRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/CyclingPedalingCadenceRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/CyclingPedalingCadenceRecordTest.java
index ff7a69a..55d8055 100644
--- a/tests/cts/src/android/healthconnect/cts/CyclingPedalingCadenceRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/CyclingPedalingCadenceRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.CyclingPedalingCadenceRecord.RPM_AVG;
 import static android.health.connect.datatypes.CyclingPedalingCadenceRecord.RPM_MAX;
@@ -42,6 +42,7 @@
 import android.health.connect.datatypes.Device;
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -51,6 +52,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -71,6 +73,11 @@
     private static final String TAG = "CyclingPedalingCadenceRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/DistanceRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/DistanceRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/DistanceRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/DistanceRecordTest.java
index 547be9f..6ed412a 100644
--- a/tests/cts/src/android/healthconnect/cts/DistanceRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/DistanceRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.DistanceRecord.DISTANCE_TOTAL;
 
@@ -40,6 +40,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Length;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -50,6 +51,7 @@
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.BeforeClass;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -69,6 +71,11 @@
     private static final String TAG = "DistanceRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
@@ -87,6 +94,9 @@
 
     @BeforeClass
     public static void setup() throws InterruptedException {
+        if (!TestUtils.isHardwareSupported()) {
+            return;
+        }
         TestUtils.verifyDeleteRecords(
                 DistanceRecord.class,
                 new TimeInstantRangeFilter.Builder()
diff --git a/tests/cts/src/android/healthconnect/cts/ElevationGainedRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/ElevationGainedRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/ElevationGainedRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/ElevationGainedRecordTest.java
index 7b678e3..771462b 100644
--- a/tests/cts/src/android/healthconnect/cts/ElevationGainedRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/ElevationGainedRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.ElevationGainedRecord.ELEVATION_GAINED_TOTAL;
 
@@ -40,6 +40,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Length;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -49,6 +50,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -68,6 +70,11 @@
     private static final String TAG = "ElevationGainedRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/ExerciseLapTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/ExerciseLapTest.java
similarity index 92%
rename from tests/cts/src/android/healthconnect/cts/ExerciseLapTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/ExerciseLapTest.java
index 819bf64..ae2b597 100644
--- a/tests/cts/src/android/healthconnect/cts/ExerciseLapTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/ExerciseLapTest.java
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
-import static android.healthconnect.cts.utils.TestUtils.SESSION_END_TIME;
-import static android.healthconnect.cts.utils.TestUtils.SESSION_START_TIME;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_END_TIME;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_START_TIME;
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -25,7 +26,6 @@
 import android.health.connect.datatypes.ExerciseSessionRecord;
 import android.health.connect.datatypes.ExerciseSessionType;
 import android.health.connect.datatypes.units.Length;
-import android.healthconnect.cts.utils.TestUtils;
 
 import org.junit.Test;
 
@@ -71,7 +71,7 @@
     @Test(expected = IllegalArgumentException.class)
     public void testLaps_lapStartTimeIllegal_throwsException() {
         new ExerciseSessionRecord.Builder(
-                        TestUtils.generateMetadata(),
+                        generateMetadata(),
                         SESSION_START_TIME,
                         SESSION_START_TIME.plusSeconds(200),
                         ExerciseSessionType.EXERCISE_SESSION_TYPE_CALISTHENICS)
@@ -87,7 +87,7 @@
     @Test(expected = IllegalArgumentException.class)
     public void testLaps_lapEndTimeIllegal_throwsException() {
         new ExerciseSessionRecord.Builder(
-                        TestUtils.generateMetadata(),
+                        generateMetadata(),
                         SESSION_START_TIME,
                         SESSION_START_TIME.plusSeconds(200),
                         ExerciseSessionType.EXERCISE_SESSION_TYPE_CALISTHENICS)
@@ -103,7 +103,7 @@
     @Test(expected = IllegalArgumentException.class)
     public void testLaps_lapsOverlaps_throwsException() {
         new ExerciseSessionRecord.Builder(
-                        TestUtils.generateMetadata(),
+                        generateMetadata(),
                         SESSION_START_TIME,
                         SESSION_END_TIME,
                         ExerciseSessionType.EXERCISE_SESSION_TYPE_CALISTHENICS)
diff --git a/tests/cts/src/android/healthconnect/cts/ExerciseRouteTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/ExerciseRouteTest.java
similarity index 84%
rename from tests/cts/src/android/healthconnect/cts/ExerciseRouteTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/ExerciseRouteTest.java
index cc07aee..5dcbaf4 100644
--- a/tests/cts/src/android/healthconnect/cts/ExerciseRouteTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/ExerciseRouteTest.java
@@ -14,7 +14,10 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
+
+import static android.healthconnect.cts.utils.DataFactory.SESSION_START_TIME;
+import static android.healthconnect.cts.utils.DataFactory.buildLocationTimePoint;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -22,7 +25,6 @@
 
 import android.health.connect.datatypes.ExerciseRoute;
 import android.health.connect.datatypes.units.Length;
-import android.healthconnect.cts.utils.TestUtils;
 import android.os.Parcel;
 
 import androidx.test.runner.AndroidJUnit4;
@@ -78,47 +80,38 @@
 
     @Test(expected = IllegalArgumentException.class)
     public void testExerciseRouteLocation_latitudeIsInvalid_throwsException() {
-        ExerciseRoute.Location point =
-                new ExerciseRoute.Location.Builder(
-                                DEFAULT_TIME, /* latitude= */ -120, DEFAULT_LONGITUDE)
-                        .build();
+        new ExerciseRoute.Location.Builder(DEFAULT_TIME, /* latitude= */ -120, DEFAULT_LONGITUDE)
+                .build();
         fail("Must return error if latitude is illegal");
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testExerciseRouteLocation_longitudeIsInvalid_throwsException() {
-        ExerciseRoute.Location point =
-                new ExerciseRoute.Location.Builder(
-                                DEFAULT_TIME, DEFAULT_LATITUDE, /* longitude= */ 400)
-                        .build();
+        new ExerciseRoute.Location.Builder(DEFAULT_TIME, DEFAULT_LATITUDE, /* longitude= */ 400)
+                .build();
         fail("Must return error if longitude is illegal");
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testExerciseRouteLocation_horizontalAccuracyIsInvalid_throwsException() {
-        ExerciseRoute.Location point =
-                new ExerciseRoute.Location.Builder(
-                                DEFAULT_TIME, DEFAULT_LATITUDE, DEFAULT_LONGITUDE)
-                        .setHorizontalAccuracy(Length.fromMeters(-5))
-                        .build();
+        new ExerciseRoute.Location.Builder(DEFAULT_TIME, DEFAULT_LATITUDE, DEFAULT_LONGITUDE)
+                .setHorizontalAccuracy(Length.fromMeters(-5))
+                .build();
         fail("Must return error if horizontal accuracy is illegal");
     }
 
     @Test(expected = IllegalArgumentException.class)
     public void testExerciseRouteLocation_verticalAccuracyIsInvalid_throwsException() {
-        ExerciseRoute.Location point =
-                new ExerciseRoute.Location.Builder(
-                                DEFAULT_TIME, DEFAULT_LATITUDE, DEFAULT_LONGITUDE)
-                        .setHorizontalAccuracy(Length.fromMeters(-5))
-                        .build();
+        new ExerciseRoute.Location.Builder(DEFAULT_TIME, DEFAULT_LATITUDE, DEFAULT_LONGITUDE)
+                .setHorizontalAccuracy(Length.fromMeters(-5))
+                .build();
         fail("Must return error if vertical accuracy is illegal");
     }
 
     @Test
     public void testExerciseRouteLocation_buildRoute_success() {
         ExerciseRoute route =
-                new ExerciseRoute(
-                        List.of(TestUtils.buildLocationTimePoint(TestUtils.SESSION_START_TIME)));
+                new ExerciseRoute(List.of(buildLocationTimePoint(SESSION_START_TIME)));
         assertThat(route.getRouteLocations()).hasSize(1);
     }
 
diff --git a/tests/cts/src/android/healthconnect/cts/ExerciseSegmentTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/ExerciseSegmentTest.java
similarity index 93%
rename from tests/cts/src/android/healthconnect/cts/ExerciseSegmentTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/ExerciseSegmentTest.java
index 9536255..6b1e4a7 100644
--- a/tests/cts/src/android/healthconnect/cts/ExerciseSegmentTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/ExerciseSegmentTest.java
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
-import static android.healthconnect.cts.utils.TestUtils.SESSION_END_TIME;
-import static android.healthconnect.cts.utils.TestUtils.SESSION_START_TIME;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_END_TIME;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_START_TIME;
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -25,7 +26,6 @@
 import android.health.connect.datatypes.ExerciseSegmentType;
 import android.health.connect.datatypes.ExerciseSessionRecord;
 import android.health.connect.datatypes.ExerciseSessionType;
-import android.healthconnect.cts.utils.TestUtils;
 
 import org.junit.Test;
 
@@ -81,7 +81,7 @@
     @Test(expected = IllegalArgumentException.class)
     public void testExerciseSegment_lapStartTimeIllegal_throwsException() {
         new ExerciseSessionRecord.Builder(
-                        TestUtils.generateMetadata(),
+                        generateMetadata(),
                         SESSION_START_TIME,
                         SESSION_START_TIME.plusSeconds(200),
                         ExerciseSessionType.EXERCISE_SESSION_TYPE_BADMINTON)
@@ -98,7 +98,7 @@
     @Test(expected = IllegalArgumentException.class)
     public void testExerciseSegment_lapEndTimeIllegal_throwsException() {
         new ExerciseSessionRecord.Builder(
-                        TestUtils.generateMetadata(),
+                        generateMetadata(),
                         SESSION_START_TIME,
                         SESSION_START_TIME.plusSeconds(200),
                         ExerciseSessionType.EXERCISE_SESSION_TYPE_BADMINTON)
@@ -115,7 +115,7 @@
     @Test(expected = IllegalArgumentException.class)
     public void testExerciseSegment_segmentsOverlap_throwsException() {
         new ExerciseSessionRecord.Builder(
-                        TestUtils.generateMetadata(),
+                        generateMetadata(),
                         SESSION_START_TIME,
                         SESSION_END_TIME,
                         ExerciseSessionType.EXERCISE_SESSION_TYPE_HIGH_INTENSITY_INTERVAL_TRAINING)
diff --git a/tests/cts/src/android/healthconnect/cts/ExerciseSessionRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/ExerciseSessionRecordTest.java
similarity index 87%
rename from tests/cts/src/android/healthconnect/cts/ExerciseSessionRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/ExerciseSessionRecordTest.java
index 0a70837..69390a0 100644
--- a/tests/cts/src/android/healthconnect/cts/ExerciseSessionRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/ExerciseSessionRecordTest.java
@@ -14,12 +14,15 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
-import static android.healthconnect.cts.utils.TestUtils.SESSION_END_TIME;
-import static android.healthconnect.cts.utils.TestUtils.SESSION_START_TIME;
-import static android.healthconnect.cts.utils.TestUtils.buildExerciseSession;
-import static android.healthconnect.cts.utils.TestUtils.buildLocationTimePoint;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_END_TIME;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_START_TIME;
+import static android.healthconnect.cts.utils.DataFactory.buildExerciseRoute;
+import static android.healthconnect.cts.utils.DataFactory.buildExerciseSession;
+import static android.healthconnect.cts.utils.DataFactory.buildLocationTimePoint;
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
+import static android.healthconnect.cts.utils.TestUtils.distinctByUuid;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -43,6 +46,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Length;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -50,6 +54,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -64,10 +69,10 @@
 @RunWith(AndroidJUnit4.class)
 public class ExerciseSessionRecordTest {
 
-    /** Constructs a new object. */
-    public ExerciseSessionRecordTest() {
-        super();
-    }
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
 
     @After
     public void tearDown() throws InterruptedException {
@@ -96,13 +101,13 @@
     @Test
     public void testBuildSession_noException() {
         for (int i = 0; i < 200; i++) {
-            TestUtils.buildExerciseSession();
+            buildExerciseSession();
         }
     }
 
     @Test
     public void testExerciseSession_buildEqualSessions_equalsReturnsTrue() {
-        Metadata metadata = TestUtils.generateMetadata();
+        Metadata metadata = generateMetadata();
         ExerciseSessionRecord record =
                 new ExerciseSessionRecord.Builder(
                                 metadata,
@@ -122,9 +127,9 @@
 
     @Test
     public void testExerciseSession_buildSessionWithAllFields_buildCorrectObject() {
-        ExerciseRoute route = TestUtils.buildExerciseRoute();
-        CharSequence notes = "rain";
-        CharSequence title = "Morning training";
+        ExerciseRoute route = buildExerciseRoute();
+        String notes = "rain";
+        String title = "Morning training";
         List<ExerciseSegment> segmentList =
                 List.of(
                         new ExerciseSegment.Builder(
@@ -141,7 +146,7 @@
                                 .build());
         ExerciseSessionRecord record =
                 new ExerciseSessionRecord.Builder(
-                                TestUtils.generateMetadata(),
+                                generateMetadata(),
                                 SESSION_START_TIME,
                                 SESSION_END_TIME,
                                 ExerciseSessionType.EXERCISE_SESSION_TYPE_FOOTBALL_AMERICAN)
@@ -160,16 +165,16 @@
         assertThat(record.getStartZoneOffset()).isEqualTo(ZoneOffset.MIN);
         assertThat(record.getExerciseType())
                 .isEqualTo(ExerciseSessionType.EXERCISE_SESSION_TYPE_FOOTBALL_AMERICAN);
-        assertThat(record.getNotes()).isEqualTo(notes);
+        assertThat(record.getNotes().toString()).isEqualTo(notes);
         assertThat(record.getSegments()).isEqualTo(segmentList);
         assertThat(record.getLaps()).isEqualTo(lapsList);
-        assertThat(record.getTitle()).isEqualTo(title);
+        assertThat(record.getTitle().toString()).isEqualTo(title);
     }
 
     @Test
     public void testUpdateRecord_updateToRecordWithoutRouteWithWritePerm_routeIsNullAfterUpdate()
             throws InterruptedException {
-        ExerciseRoute route = TestUtils.buildExerciseRoute();
+        ExerciseRoute route = buildExerciseRoute();
         ExerciseSessionRecord record =
                 new ExerciseSessionRecord.Builder(
                                 new Metadata.Builder().build(),
@@ -294,12 +299,12 @@
                 ZoneOffset.systemDefault().getRules().getOffset(Instant.now());
         final ZoneOffset startZoneOffset = ZoneOffset.UTC;
         final ZoneOffset endZoneOffset = ZoneOffset.MAX;
-        ExerciseRoute route = TestUtils.buildExerciseRoute();
+        ExerciseRoute route = buildExerciseRoute();
         CharSequence notes = "rain";
         CharSequence title = "Morning training";
         ExerciseSessionRecord.Builder builder =
                 new ExerciseSessionRecord.Builder(
-                                TestUtils.generateMetadata(),
+                                generateMetadata(),
                                 SESSION_START_TIME,
                                 SESSION_END_TIME,
                                 ExerciseSessionType.EXERCISE_SESSION_TYPE_FOOTBALL_AMERICAN)
@@ -321,8 +326,7 @@
 
     @Test
     public void testInsertRecord_apiReturnsRequestedRecords() throws InterruptedException {
-        List<Record> records =
-                Arrays.asList(TestUtils.buildExerciseSession(), TestUtils.buildExerciseSession());
+        List<Record> records = Arrays.asList(buildExerciseSession(), buildExerciseSession());
         List<Record> insertedRecords = TestUtils.insertRecords(records);
         assertThat(records.size()).isEqualTo(insertedRecords.size());
         assertThat(records).containsExactlyElementsIn(insertedRecords);
@@ -330,7 +334,7 @@
 
     @Test
     public void testReadById_insertAndReadById_recordsAreEqual() throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildExerciseSession(), buildSessionMinimal());
+        List<Record> records = List.of(buildExerciseSession(), buildSessionMinimal());
         TestUtils.insertRecords(records);
 
         ReadRecordsRequestUsingIds.Builder<ExerciseSessionRecord> request =
@@ -343,7 +347,7 @@
 
     @Test
     public void testReadById_insertAndReadByIdOne_recordsAreEqual() throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildExerciseSession());
+        List<Record> records = List.of(buildExerciseSession());
         TestUtils.insertRecords(records);
 
         ReadRecordsRequestUsingIds.Builder<ExerciseSessionRecord> request =
@@ -362,7 +366,7 @@
     @Test
     public void testReadByClientId_insertAndReadByClientId_recordsAreEqual()
             throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildExerciseSession(), buildSessionMinimal());
+        List<Record> records = List.of(buildExerciseSession(), buildSessionMinimal());
         TestUtils.insertRecords(records);
 
         ReadRecordsRequestUsingIds.Builder<ExerciseSessionRecord> request =
@@ -376,7 +380,7 @@
     @Test
     public void testReadByClientId_insertAndReadByDefaultFilter_filteredAll()
             throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildExerciseSession(), buildSessionMinimal());
+        List<Record> records = List.of(buildExerciseSession(), buildSessionMinimal());
         assertThat(TestUtils.insertRecords(records)).hasSize(2);
 
         List<ExerciseSessionRecord> readRecords =
@@ -389,7 +393,7 @@
     @Test
     public void testReadByClientId_insertAndReadByTimeFilter_filteredCorrectly()
             throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildExerciseSession(), buildSessionMinimal());
+        List<Record> records = List.of(buildExerciseSession(), buildSessionMinimal());
         TestUtils.insertRecords(records);
 
         TimeInstantRangeFilter filter =
@@ -413,7 +417,7 @@
     @Test
     public void testDeleteRecords_insertAndDeleteById_recordsNotFoundAnymore()
             throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildExerciseSession(), buildSessionMinimal());
+        List<Record> records = List.of(buildExerciseSession(), buildSessionMinimal());
         List<Record> insertedRecords = TestUtils.insertRecords(records);
 
         TestUtils.assertRecordFound(
@@ -588,12 +592,34 @@
         assertThat(response.getDeletedLogs()).isEmpty();
     }
 
+    @Test
+    public void insertRecords_withDuplicatedClientRecordId_readNoDuplicates() throws Exception {
+        int distinctRecordCount = 10;
+        List<ExerciseSessionRecord> records = new ArrayList<>();
+        Instant now = Instant.now();
+        for (int i = 0; i < distinctRecordCount; i++) {
+            ExerciseSessionRecord record =
+                    buildSession(
+                            /* startTime= */ now.minusSeconds(i + 1),
+                            /* endTime= */ now.minusSeconds(i),
+                            /* clientRecordId= */ "client_id_" + i);
+
+            records.add(record);
+            records.add(record); // Add each record twice
+        }
+
+        List<Record> insertedRecords = TestUtils.insertRecords(records);
+        assertThat(insertedRecords.size()).isEqualTo(records.size());
+
+        List<Record> distinctRecords = distinctByUuid(insertedRecords);
+        assertThat(distinctRecords.size()).isEqualTo(distinctRecordCount);
+
+        readAndAssertEquals(distinctRecords);
+    }
+
     private ExerciseSessionRecord buildRecordWithOneSegment(int sessionType, int segmentType) {
         return new ExerciseSessionRecord.Builder(
-                        TestUtils.generateMetadata(),
-                        SESSION_START_TIME,
-                        SESSION_END_TIME,
-                        sessionType)
+                        generateMetadata(), SESSION_START_TIME, SESSION_END_TIME, sessionType)
                 .setSegments(
                         List.of(
                                 new ExerciseSegment.Builder(
@@ -641,8 +667,14 @@
     }
 
     private static ExerciseSessionRecord buildSession(Instant startTime, Instant endTime) {
+        return buildSession(
+                startTime, endTime, /* clientRecordId= */ "ExerciseSessionClient" + Math.random());
+    }
+
+    private static ExerciseSessionRecord buildSession(
+            Instant startTime, Instant endTime, String clientRecordId) {
         return new ExerciseSessionRecord.Builder(
-                        TestUtils.generateMetadata(),
+                        buildMetadata(clientRecordId),
                         startTime,
                         endTime,
                         ExerciseSessionType.EXERCISE_SESSION_TYPE_FOOTBALL_AMERICAN)
@@ -656,18 +688,22 @@
 
     private static ExerciseSessionRecord buildSessionMinimal() {
         return new ExerciseSessionRecord.Builder(
-                        new Metadata.Builder()
-                                .setDataOrigin(
-                                        new DataOrigin.Builder()
-                                                .setPackageName("android.healthconnect.cts")
-                                                .build())
-                                .setId(UUID.randomUUID().toString())
-                                .setClientRecordId("ExerciseSessionClient" + Math.random())
-                                .setRecordingMethod(Metadata.RECORDING_METHOD_ACTIVELY_RECORDED)
-                                .build(),
+                        buildMetadata("ExerciseSessionClient" + Math.random()),
                         SESSION_START_TIME,
                         SESSION_END_TIME,
                         ExerciseSessionType.EXERCISE_SESSION_TYPE_FOOTBALL_AMERICAN)
                 .build();
     }
+
+    private static Metadata buildMetadata(String clientRecordId) {
+        return new Metadata.Builder()
+                .setDataOrigin(
+                        new DataOrigin.Builder()
+                                .setPackageName("android.healthconnect.cts")
+                                .build())
+                .setId(UUID.randomUUID().toString())
+                .setClientRecordId(clientRecordId)
+                .setRecordingMethod(Metadata.RECORDING_METHOD_ACTIVELY_RECORDED)
+                .build();
+    }
 }
diff --git a/tests/cts/src/android/healthconnect/cts/FloorsClimbedRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/FloorsClimbedRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/FloorsClimbedRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/FloorsClimbedRecordTest.java
index e2b3ff6..59a1cf8 100644
--- a/tests/cts/src/android/healthconnect/cts/FloorsClimbedRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/FloorsClimbedRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.FloorsClimbedRecord.FLOORS_CLIMBED_TOTAL;
 
@@ -38,6 +38,7 @@
 import android.health.connect.datatypes.FloorsClimbedRecord;
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -46,6 +47,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -63,6 +65,11 @@
     private static final String TAG = "FloorsClimbedRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/HeartRateRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/HeartRateRecordTest.java
similarity index 96%
rename from tests/cts/src/android/healthconnect/cts/HeartRateRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/HeartRateRecordTest.java
index 623c8ed..a8f62ff 100644
--- a/tests/cts/src/android/healthconnect/cts/HeartRateRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/HeartRateRecordTest.java
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.HeartRateRecord.BPM_AVG;
 import static android.health.connect.datatypes.HeartRateRecord.BPM_MAX;
 import static android.health.connect.datatypes.HeartRateRecord.BPM_MIN;
 import static android.health.connect.datatypes.HeartRateRecord.HEART_MEASUREMENTS_COUNT;
+import static android.healthconnect.cts.utils.DataFactory.getHeartRateRecord;
 import static android.healthconnect.cts.utils.TestUtils.readRecordsWithPagination;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -46,6 +47,7 @@
 import android.health.connect.datatypes.HeartRateRecord;
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -55,6 +57,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -74,6 +77,12 @@
 @RunWith(AndroidJUnit4.class)
 public class HeartRateRecordTest {
     private static final String TAG = "HeartRateRecordTest";
+    private static final String PACKAGE_NAME = "android.healthconnect.cts";
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
 
     @After
     public void tearDown() throws InterruptedException {
@@ -86,8 +95,6 @@
         TestUtils.deleteAllStagedRemoteData();
     }
 
-    private static final String PACKAGE_NAME = "android.healthconnect.cts";
-
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
@@ -224,8 +231,8 @@
     public void testReadHeartRateRecordUsingFilters_withPageSize() throws InterruptedException {
         List<Record> recordList =
                 Arrays.asList(
-                        TestUtils.getHeartRateRecord(72, Instant.now().minus(1, ChronoUnit.DAYS)),
-                        TestUtils.getHeartRateRecord(72, Instant.now().minus(2, ChronoUnit.DAYS)));
+                        getHeartRateRecord(72, Instant.now().minus(1, ChronoUnit.DAYS)),
+                        getHeartRateRecord(72, Instant.now().minus(2, ChronoUnit.DAYS)));
         TestUtils.insertRecords(recordList);
         ReadRecordsResponse<HeartRateRecord> newHeartRecords =
                 readRecordsWithPagination(
@@ -239,10 +246,10 @@
     public void testReadHeartRateRecordUsingFilters_withPageToken() throws InterruptedException {
         List<Record> recordList =
                 Arrays.asList(
-                        TestUtils.getHeartRateRecord(72, Instant.now().minusMillis(1000)),
-                        TestUtils.getHeartRateRecord(72, Instant.now().minusMillis(2000)),
-                        TestUtils.getHeartRateRecord(72, Instant.now().minusMillis(3000)),
-                        TestUtils.getHeartRateRecord(72, Instant.now().minusMillis(4000)));
+                        getHeartRateRecord(72, Instant.now().minusMillis(1000)),
+                        getHeartRateRecord(72, Instant.now().minusMillis(2000)),
+                        getHeartRateRecord(72, Instant.now().minusMillis(3000)),
+                        getHeartRateRecord(72, Instant.now().minusMillis(4000)));
         TestUtils.insertRecords(recordList);
         ReadRecordsResponse<HeartRateRecord> oldHeartRecords =
                 readRecordsWithPagination(
@@ -264,8 +271,7 @@
 
     @Test
     public void testReadHeartRateRecordUsingFilters_nextPageTokenEnd() throws InterruptedException {
-        List<Record> recordList =
-                Arrays.asList(TestUtils.getHeartRateRecord(), TestUtils.getHeartRateRecord());
+        List<Record> recordList = Arrays.asList(getHeartRateRecord(), getHeartRateRecord());
         TestUtils.insertRecords(recordList);
         ReadRecordsResponse<HeartRateRecord> oldHeartRecords =
                 readRecordsWithPagination(
@@ -538,12 +544,9 @@
     @Test
     public void testBpmAggregation_timeRange_not_present() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.VITALS);
-
         List<Record> records =
                 Arrays.asList(
-                        TestUtils.getHeartRateRecord(71),
-                        TestUtils.getHeartRateRecord(72),
-                        TestUtils.getHeartRateRecord(73));
+                        getHeartRateRecord(71), getHeartRateRecord(72), getHeartRateRecord(73));
         AggregateRecordsResponse<Long> response =
                 TestUtils.getAggregateResponse(
                         new AggregateRecordsRequest.Builder<Long>(
@@ -567,7 +570,6 @@
     @Test
     public void testBpmAggregation_withDataOrigin_correct() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.VITALS);
-
         Context context = ApplicationProvider.getApplicationContext();
         List<Record> records =
                 Arrays.asList(
@@ -607,12 +609,9 @@
     @Test
     public void testBpmAggregation_withDataOrigin_incorrect() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.VITALS);
-
         List<Record> records =
                 Arrays.asList(
-                        TestUtils.getHeartRateRecord(71),
-                        TestUtils.getHeartRateRecord(72),
-                        TestUtils.getHeartRateRecord(73));
+                        getHeartRateRecord(71), getHeartRateRecord(72), getHeartRateRecord(73));
         AggregateRecordsResponse<Long> response =
                 TestUtils.getAggregateResponse(
                         new AggregateRecordsRequest.Builder<Long>(
@@ -687,7 +686,6 @@
     @Test
     public void testBpmAggregation_groupByDuration() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.VITALS);
-
         Instant start = Instant.now().minus(3, ChronoUnit.DAYS);
         Instant end = start.plus(3, ChronoUnit.DAYS);
         insertHeartRateRecordsInPastDays(4);
@@ -754,7 +752,6 @@
     @Test
     public void testHeartAggregation_measurement_count() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.VITALS);
-
         List<Record> records =
                 Arrays.asList(
                         getBaseHeartRateRecord(71),
@@ -909,7 +906,6 @@
     @Test
     public void testAggregateLocalFilter_minOffsetRecord() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.VITALS);
-
         LocalDateTime endTimeLocal = LocalDateTime.now(ZoneOffset.UTC);
         Instant endTimeInstant = Instant.now();
 
@@ -1012,12 +1008,9 @@
         for (int i = numDays; i > 0; i--) {
             List<Record> records =
                     Arrays.asList(
-                            TestUtils.getHeartRateRecord(
-                                    71, Instant.now().minus(i, ChronoUnit.DAYS)),
-                            TestUtils.getHeartRateRecord(
-                                    72, Instant.now().minus(i, ChronoUnit.DAYS)),
-                            TestUtils.getHeartRateRecord(
-                                    73, Instant.now().minus(i, ChronoUnit.DAYS)));
+                            getHeartRateRecord(71, Instant.now().minus(i, ChronoUnit.DAYS)),
+                            getHeartRateRecord(72, Instant.now().minus(i, ChronoUnit.DAYS)),
+                            getHeartRateRecord(73, Instant.now().minus(i, ChronoUnit.DAYS)));
 
             TestUtils.insertRecords(records);
         }
diff --git a/tests/cts/src/android/healthconnect/cts/HeartRateVariabilityRmssdRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/HeartRateVariabilityRmssdRecordTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/HeartRateVariabilityRmssdRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/HeartRateVariabilityRmssdRecordTest.java
index 72a0fbb..2c5c81c 100644
--- a/tests/cts/src/android/healthconnect/cts/HeartRateVariabilityRmssdRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/HeartRateVariabilityRmssdRecordTest.java
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
+
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -34,6 +36,7 @@
 import android.health.connect.datatypes.HeartRateVariabilityRmssdRecord;
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -42,6 +45,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,6 +63,11 @@
     private static final String TAG = "HeartRateVariabilityRmssdRecordTest";
     private static final Instant TIME = Instant.ofEpochMilli((long) 1e9);
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
@@ -331,14 +340,13 @@
     @Test
     public void testHeartRateVariabilityRmssd_buildSession_buildCorrectObject() {
         HeartRateVariabilityRmssdRecord record =
-                new HeartRateVariabilityRmssdRecord.Builder(TestUtils.generateMetadata(), TIME, 1.3)
-                        .build();
+                new HeartRateVariabilityRmssdRecord.Builder(generateMetadata(), TIME, 1.3).build();
         assertThat(record.getTime()).isEqualTo(TIME);
     }
 
     @Test
     public void testHeartRateVariabilityRmssd_buildEqualSessions_equalsReturnsTrue() {
-        Metadata metadata = TestUtils.generateMetadata();
+        Metadata metadata = generateMetadata();
         HeartRateVariabilityRmssdRecord record =
                 new HeartRateVariabilityRmssdRecord.Builder(metadata, TIME, 1.3).build();
         HeartRateVariabilityRmssdRecord record2 =
@@ -349,7 +357,7 @@
     @Test
     public void testHeartRateVariabilityRmssd_buildSessionWithAllFields_buildCorrectObject() {
         HeartRateVariabilityRmssdRecord record =
-                new HeartRateVariabilityRmssdRecord.Builder(TestUtils.generateMetadata(), TIME, 1.3)
+                new HeartRateVariabilityRmssdRecord.Builder(generateMetadata(), TIME, 1.3)
                         .setZoneOffset(ZoneOffset.MAX)
                         .build();
         assertThat(record.getZoneOffset()).isEqualTo(ZoneOffset.MAX);
diff --git a/tests/cts/src/android/healthconnect/cts/HeightRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/HeightRecordTest.java
similarity index 94%
rename from tests/cts/src/android/healthconnect/cts/HeightRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/HeightRecordTest.java
index 5022b9c..20cf13d 100644
--- a/tests/cts/src/android/healthconnect/cts/HeightRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/HeightRecordTest.java
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.HeightRecord.HEIGHT_AVG;
 import static android.health.connect.datatypes.HeightRecord.HEIGHT_MAX;
 import static android.health.connect.datatypes.HeightRecord.HEIGHT_MIN;
+import static android.healthconnect.cts.utils.TestUtils.distinctByUuid;
+import static android.healthconnect.cts.utils.TestUtils.insertRecords;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -42,6 +44,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Length;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -51,6 +54,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -70,6 +74,11 @@
     private static final String TAG = "HeightRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
@@ -522,6 +531,26 @@
                 .build();
     }
 
+    @Test
+    public void insertRecords_withDuplicatedClientRecordId_readNoDuplicates() throws Exception {
+        int distinctRecordCount = 10;
+        List<HeightRecord> records = new ArrayList<>();
+        Instant now = Instant.now();
+        for (int i = 0; i < distinctRecordCount; i++) {
+            HeightRecord record =
+                    getCompleteHeightRecord(
+                            now.minusMillis(i), /* clientRecordId= */ "client_id_" + i);
+
+            records.add(record);
+            records.add(record); // Add each record twice
+        }
+
+        List<Record> distinctRecords = distinctByUuid(insertRecords(records));
+        assertThat(distinctRecords.size()).isEqualTo(distinctRecordCount);
+
+        readHeightRecordUsingIds(distinctRecords);
+    }
+
     HeightRecord getHeightRecord_update(Record record, String id, String clientRecordId) {
         Metadata metadata = record.getMetadata();
         Metadata metadataWithId =
@@ -561,6 +590,10 @@
     }
 
     private static HeightRecord getCompleteHeightRecord() {
+        return getCompleteHeightRecord(Instant.now(), /* clientRecordId= */ "HR" + Math.random());
+    }
+
+    private static HeightRecord getCompleteHeightRecord(Instant time, String clientRecordId) {
         Device device =
                 new Device.Builder()
                         .setManufacturer("google")
@@ -571,11 +604,10 @@
                 new DataOrigin.Builder().setPackageName("android.healthconnect.cts").build();
         Metadata.Builder testMetadataBuilder = new Metadata.Builder();
         testMetadataBuilder.setDevice(device).setDataOrigin(dataOrigin);
-        testMetadataBuilder.setClientRecordId("HR" + Math.random());
+        testMetadataBuilder.setClientRecordId(clientRecordId);
         testMetadataBuilder.setRecordingMethod(Metadata.RECORDING_METHOD_ACTIVELY_RECORDED);
 
-        return new HeightRecord.Builder(
-                        testMetadataBuilder.build(), Instant.now(), Length.fromMeters(1.0))
+        return new HeightRecord.Builder(testMetadataBuilder.build(), time, Length.fromMeters(1.0))
                 .setZoneOffset(ZoneOffset.systemDefault().getRules().getOffset(Instant.now()))
                 .build();
     }
diff --git a/tests/cts/src/android/healthconnect/cts/HydrationRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/HydrationRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/HydrationRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/HydrationRecordTest.java
index 28b1b65..ff9e505 100644
--- a/tests/cts/src/android/healthconnect/cts/HydrationRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/HydrationRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.HydrationRecord.VOLUME_TOTAL;
 
@@ -40,16 +40,16 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Volume;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.core.app.ApplicationProvider;
-import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
-import org.junit.runner.RunWith;
 
 import java.time.Instant;
 import java.time.ZoneOffset;
@@ -61,11 +61,15 @@
 import java.util.Set;
 import java.util.UUID;
 
-@RunWith(AndroidJUnit4.class)
 public class HydrationRecordTest {
     private static final String TAG = "HydrationRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/IntermenstrualBleedingRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/IntermenstrualBleedingRecordTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/IntermenstrualBleedingRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/IntermenstrualBleedingRecordTest.java
index f706f88..99105f3 100644
--- a/tests/cts/src/android/healthconnect/cts/IntermenstrualBleedingRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/IntermenstrualBleedingRecordTest.java
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
+
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -34,6 +36,7 @@
 import android.health.connect.datatypes.IntermenstrualBleedingRecord;
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -42,6 +45,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,6 +63,11 @@
     private static final String TAG = "IntermenstrualBleedingRecordTest";
     private static final Instant TIME = Instant.ofEpochMilli((long) 1e9);
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
@@ -329,14 +338,13 @@
     @Test
     public void testIntermenstrualBleeding_buildSession_buildCorrectObject() {
         IntermenstrualBleedingRecord record =
-                new IntermenstrualBleedingRecord.Builder(TestUtils.generateMetadata(), TIME)
-                        .build();
+                new IntermenstrualBleedingRecord.Builder(generateMetadata(), TIME).build();
         assertThat(record.getTime()).isEqualTo(TIME);
     }
 
     @Test
     public void testIntermenstrualBleeding_buildEqualSessions_equalsReturnsTrue() {
-        Metadata metadata = TestUtils.generateMetadata();
+        Metadata metadata = generateMetadata();
         IntermenstrualBleedingRecord record =
                 new IntermenstrualBleedingRecord.Builder(metadata, TIME).build();
         IntermenstrualBleedingRecord record2 =
@@ -347,7 +355,7 @@
     @Test
     public void testIntermenstrualBleeding_buildSessionWithAllFields_buildCorrectObject() {
         IntermenstrualBleedingRecord record =
-                new IntermenstrualBleedingRecord.Builder(TestUtils.generateMetadata(), TIME)
+                new IntermenstrualBleedingRecord.Builder(generateMetadata(), TIME)
                         .setZoneOffset(ZoneOffset.MAX)
                         .build();
         assertThat(record.getZoneOffset()).isEqualTo(ZoneOffset.MAX);
diff --git a/tests/cts/src/android/healthconnect/cts/LeanBodyMassRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/LeanBodyMassRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/LeanBodyMassRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/LeanBodyMassRecordTest.java
index cde7e32..f8d3800 100644
--- a/tests/cts/src/android/healthconnect/cts/LeanBodyMassRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/LeanBodyMassRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -35,6 +35,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Mass;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -43,6 +44,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,6 +61,11 @@
 public class LeanBodyMassRecordTest {
     private static final String TAG = "LeanBodyMassRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/MenstruationFlowRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/MenstruationFlowRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/MenstruationFlowRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/MenstruationFlowRecordTest.java
index f48a814..f2deaa9 100644
--- a/tests/cts/src/android/healthconnect/cts/MenstruationFlowRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/MenstruationFlowRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -34,6 +34,7 @@
 import android.health.connect.datatypes.MenstruationFlowRecord;
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -42,6 +43,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -58,6 +60,11 @@
 public class MenstruationFlowRecordTest {
     private static final String TAG = "MenstruationFlowRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/MenstruationPeriodRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/MenstruationPeriodRecordTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/MenstruationPeriodRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/MenstruationPeriodRecordTest.java
index f87fd26..f1aade1 100644
--- a/tests/cts/src/android/healthconnect/cts/MenstruationPeriodRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/MenstruationPeriodRecordTest.java
@@ -14,7 +14,9 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
+
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -34,6 +36,7 @@
 import android.health.connect.datatypes.MenstruationPeriodRecord;
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -42,6 +45,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -60,6 +64,11 @@
     private static final Instant START_TIME = Instant.ofEpochMilli((long) 1e9);
     private static final Instant END_TIME = Instant.ofEpochMilli((long) 1e10);
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
@@ -304,8 +313,7 @@
         final ZoneOffset startZoneOffset = ZoneOffset.UTC;
         final ZoneOffset endZoneOffset = ZoneOffset.MAX;
         MenstruationPeriodRecord.Builder builder =
-                new MenstruationPeriodRecord.Builder(
-                                TestUtils.generateMetadata(), START_TIME, END_TIME)
+                new MenstruationPeriodRecord.Builder(generateMetadata(), START_TIME, END_TIME)
                         .setEndZoneOffset(ZoneOffset.MAX)
                         .setStartZoneOffset(ZoneOffset.MIN);
 
@@ -322,8 +330,7 @@
     @Test
     public void testMenstruationPeriod_buildSession_buildCorrectObject() {
         MenstruationPeriodRecord record =
-                new MenstruationPeriodRecord.Builder(
-                                TestUtils.generateMetadata(), START_TIME, END_TIME)
+                new MenstruationPeriodRecord.Builder(generateMetadata(), START_TIME, END_TIME)
                         .build();
         assertThat(record.getStartTime()).isEqualTo(START_TIME);
         assertThat(record.getEndTime()).isEqualTo(END_TIME);
@@ -331,7 +338,7 @@
 
     @Test
     public void testMenstruationPeriod_buildEqualSessions_equalsReturnsTrue() {
-        Metadata metadata = TestUtils.generateMetadata();
+        Metadata metadata = generateMetadata();
         MenstruationPeriodRecord record =
                 new MenstruationPeriodRecord.Builder(metadata, START_TIME, END_TIME).build();
         MenstruationPeriodRecord record2 =
@@ -342,8 +349,7 @@
     @Test
     public void testMenstruationPeriod_buildSessionWithAllFields_buildCorrectObject() {
         MenstruationPeriodRecord record =
-                new MenstruationPeriodRecord.Builder(
-                                TestUtils.generateMetadata(), START_TIME, END_TIME)
+                new MenstruationPeriodRecord.Builder(generateMetadata(), START_TIME, END_TIME)
                         .setEndZoneOffset(ZoneOffset.MAX)
                         .setStartZoneOffset(ZoneOffset.MIN)
                         .build();
diff --git a/tests/cts/src/android/healthconnect/cts/NutritionRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/NutritionRecordTest.java
similarity index 99%
rename from tests/cts/src/android/healthconnect/cts/NutritionRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/NutritionRecordTest.java
index 0c3848f..dda69ba 100644
--- a/tests/cts/src/android/healthconnect/cts/NutritionRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/NutritionRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.NutritionRecord.BIOTIN_TOTAL;
 import static android.health.connect.datatypes.NutritionRecord.CAFFEINE_TOTAL;
@@ -83,6 +83,7 @@
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Energy;
 import android.health.connect.datatypes.units.Mass;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -91,6 +92,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -107,6 +109,7 @@
 @RunWith(AndroidJUnit4.class)
 public class NutritionRecordTest {
     private static final String TAG = "NutritionRecordTest";
+    private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
     private List<AggregationType<Mass>> mMassAggregateTypesList =
             Arrays.asList(
@@ -151,7 +154,10 @@
                     VITAMIN_K_TOTAL,
                     ZINC_TOTAL);
 
-    private static final String PACKAGE_NAME = "android.healthconnect.cts";
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
 
     @Before
     public void setUp() throws InterruptedException {
@@ -546,7 +552,6 @@
     @Test
     public void testAggregation_NutritionEnergyValuesTotal() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.NUTRITION);
-
         List<Record> records = Arrays.asList(getCompleteNutritionRecord());
         AggregateRecordsResponse<Energy> oldResponse =
                 TestUtils.getAggregateResponse(
diff --git a/tests/cts/src/android/healthconnect/cts/OvulationTestRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/OvulationTestRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/OvulationTestRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/OvulationTestRecordTest.java
index 4d08043..ff6db76 100644
--- a/tests/cts/src/android/healthconnect/cts/OvulationTestRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/OvulationTestRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -34,6 +34,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.OvulationTestRecord;
 import android.health.connect.datatypes.Record;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -42,6 +43,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -58,6 +60,11 @@
 public class OvulationTestRecordTest {
     private static final String TAG = "OvulationTestRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/OxygenSaturationRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/OxygenSaturationRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/OxygenSaturationRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/OxygenSaturationRecordTest.java
index 559e518..cd2ee94 100644
--- a/tests/cts/src/android/healthconnect/cts/OxygenSaturationRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/OxygenSaturationRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -35,6 +35,7 @@
 import android.health.connect.datatypes.OxygenSaturationRecord;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Percentage;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -43,6 +44,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -59,6 +61,11 @@
 public class OxygenSaturationRecordTest {
     private static final String TAG = "OxygenSaturationRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/PowerRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/PowerRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/PowerRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/PowerRecordTest.java
index e75f7be..131e3bd 100644
--- a/tests/cts/src/android/healthconnect/cts/PowerRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/PowerRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.PowerRecord.POWER_AVG;
 import static android.health.connect.datatypes.PowerRecord.POWER_MAX;
@@ -42,6 +42,7 @@
 import android.health.connect.datatypes.PowerRecord;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Power;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -51,6 +52,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -70,6 +72,11 @@
     private static final String TAG = "PowerRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/RespiratoryRateRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/RespiratoryRateRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/RespiratoryRateRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/RespiratoryRateRecordTest.java
index e816d51..8add4ef 100644
--- a/tests/cts/src/android/healthconnect/cts/RespiratoryRateRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/RespiratoryRateRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -34,6 +34,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.RespiratoryRateRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -42,6 +43,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -58,6 +60,11 @@
 public class RespiratoryRateRecordTest {
     private static final String TAG = "RespiratoryRateRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/RestingHeartRateRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/RestingHeartRateRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/RestingHeartRateRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/RestingHeartRateRecordTest.java
index dbfc425..fcb4a91 100644
--- a/tests/cts/src/android/healthconnect/cts/RestingHeartRateRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/RestingHeartRateRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -37,6 +37,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.RestingHeartRateRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -46,6 +47,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -65,6 +67,11 @@
     private static final String TAG = "RestingHeartRateRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/SexualActivityRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/SexualActivityRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/SexualActivityRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/SexualActivityRecordTest.java
index 50cc1c6..3d5358c 100644
--- a/tests/cts/src/android/healthconnect/cts/SexualActivityRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/SexualActivityRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -34,6 +34,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.SexualActivityRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -42,6 +43,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -58,6 +60,11 @@
 public class SexualActivityRecordTest {
     private static final String TAG = "SexualActivityRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/SleepSessionRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/SleepSessionRecordTest.java
similarity index 90%
rename from tests/cts/src/android/healthconnect/cts/SleepSessionRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/SleepSessionRecordTest.java
index 3bd0a15..3ec4e2f 100644
--- a/tests/cts/src/android/healthconnect/cts/SleepSessionRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/SleepSessionRecordTest.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
-import static android.healthconnect.cts.utils.TestUtils.SESSION_END_TIME;
-import static android.healthconnect.cts.utils.TestUtils.SESSION_START_TIME;
-import static android.healthconnect.cts.utils.TestUtils.buildSleepSession;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_END_TIME;
+import static android.healthconnect.cts.utils.DataFactory.SESSION_START_TIME;
+import static android.healthconnect.cts.utils.DataFactory.buildSleepSession;
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -38,12 +39,14 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.SleepSessionRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.core.app.ApplicationProvider;
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 
 import java.time.Instant;
@@ -62,6 +65,11 @@
     private static final CharSequence NOTES = "felt sleepy";
     private static final CharSequence TITLE = "Afternoon nap";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
@@ -93,7 +101,7 @@
 
     @Test(expected = IllegalArgumentException.class)
     public void testSleepSession_sleepStageEndTimeIllegal_throwsException() {
-        new SleepSessionRecord.Builder(TestUtils.generateMetadata(), START_TIME, INTERMEDIATE_TIME)
+        new SleepSessionRecord.Builder(generateMetadata(), START_TIME, INTERMEDIATE_TIME)
                 .setStages(
                         List.of(
                                 new SleepSessionRecord.Stage(
@@ -106,7 +114,7 @@
 
     @Test(expected = IllegalArgumentException.class)
     public void testSleepSession_stagesOverlap_throwsException() {
-        new SleepSessionRecord.Builder(TestUtils.generateMetadata(), START_TIME, END_TIME)
+        new SleepSessionRecord.Builder(generateMetadata(), START_TIME, END_TIME)
                 .setStages(
                         List.of(
                                 new SleepSessionRecord.Stage(
@@ -144,7 +152,7 @@
                         END_TIME,
                         SleepSessionRecord.StageType.STAGE_TYPE_SLEEPING_DEEP);
         SleepSessionRecord record =
-                new SleepSessionRecord.Builder(TestUtils.generateMetadata(), START_TIME, END_TIME)
+                new SleepSessionRecord.Builder(generateMetadata(), START_TIME, END_TIME)
                         .setStages(List.of(stage1))
                         .setStages(List.of(stage2))
                         .build();
@@ -153,7 +161,7 @@
 
     @Test(expected = IllegalArgumentException.class)
     public void testSleepSession_sleepStageStartTimeIllegal_throwsException() {
-        new SleepSessionRecord.Builder(TestUtils.generateMetadata(), INTERMEDIATE_TIME, END_TIME)
+        new SleepSessionRecord.Builder(generateMetadata(), INTERMEDIATE_TIME, END_TIME)
                 .setStages(
                         List.of(
                                 new SleepSessionRecord.Stage(
@@ -169,7 +177,7 @@
     @Test
     public void testSleepSession_buildSession_buildsCorrectObject() {
         SleepSessionRecord record =
-                new SleepSessionRecord.Builder(TestUtils.generateMetadata(), START_TIME, END_TIME)
+                new SleepSessionRecord.Builder(generateMetadata(), START_TIME, END_TIME)
                         .setStages(
                                 List.of(
                                         new SleepSessionRecord.Stage(
@@ -216,7 +224,7 @@
 
     @Test
     public void testReadById_insertAndReadByIdOne_recordsAreEqual() throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildSleepSession());
+        List<Record> records = List.of(buildSleepSession());
         TestUtils.insertRecords(records);
 
         ReadRecordsRequestUsingIds.Builder<SleepSessionRecord> request =
@@ -236,7 +244,7 @@
 
     @Test
     public void testReadById_insertAndReadById_recordsAreEqual() throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildSleepSession(), buildSleepSessionMinimal());
+        List<Record> records = List.of(buildSleepSession(), buildSleepSessionMinimal());
         TestUtils.insertRecords(records);
 
         ReadRecordsRequestUsingIds.Builder<SleepSessionRecord> request =
@@ -250,7 +258,7 @@
     @Test
     public void testReadByClientId_insertAndReadByClientId_recordsAreEqual()
             throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildSleepSession(), buildSleepSessionMinimal());
+        List<Record> records = List.of(buildSleepSession(), buildSleepSessionMinimal());
         TestUtils.insertRecords(records);
 
         ReadRecordsRequestUsingIds.Builder<SleepSessionRecord> request =
@@ -264,7 +272,7 @@
     @Test
     public void testReadByClientId_insertAndReadByDefaultFilter_filteredAll()
             throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildSleepSession(), buildSleepSessionMinimal());
+        List<Record> records = List.of(buildSleepSession(), buildSleepSessionMinimal());
         TestUtils.insertRecords(records);
 
         List<SleepSessionRecord> readRecords =
@@ -277,7 +285,7 @@
     @Test
     public void testDeleteRecords_insertAndDeleteById_recordsNotFoundAnymore()
             throws InterruptedException {
-        List<Record> records = List.of(TestUtils.buildSleepSession(), buildSleepSessionMinimal());
+        List<Record> records = List.of(buildSleepSession(), buildSleepSessionMinimal());
         List<Record> insertedRecords = TestUtils.insertRecords(records);
 
         TestUtils.assertRecordFound(records.get(0).getMetadata().getId(), SleepSessionRecord.class);
@@ -296,16 +304,13 @@
             throws InterruptedException {
 
         List<Record> insertedRecords =
-                TestUtils.insertRecords(
-                        Arrays.asList(
-                                TestUtils.buildSleepSession(), TestUtils.buildSleepSession()));
+                TestUtils.insertRecords(Arrays.asList(buildSleepSession(), buildSleepSession()));
 
         // read inserted records and verify that the data is same as inserted.
         readAndAssertEquals(insertedRecords);
 
         // Generate a new set of records that will be used to perform the update operation.
-        List<Record> updateRecords =
-                Arrays.asList(TestUtils.buildSleepSession(), TestUtils.buildSleepSession());
+        List<Record> updateRecords = Arrays.asList(buildSleepSession(), buildSleepSession());
 
         // Modify the uid of the updateRecords to the uuid that was present in the insert
         // records.
@@ -328,16 +333,13 @@
     public void testUpdateRecords_invalidInputRecords_noChangeInDataBase()
             throws InterruptedException {
         List<Record> insertedRecords =
-                TestUtils.insertRecords(
-                        Arrays.asList(
-                                TestUtils.buildSleepSession(), TestUtils.buildSleepSession()));
+                TestUtils.insertRecords(Arrays.asList(buildSleepSession(), buildSleepSession()));
 
         // read inserted records and verify that the data is same as inserted.
         readAndAssertEquals(insertedRecords);
 
         // Generate a second set of records that will be used to perform the update operation.
-        List<Record> updateRecords =
-                Arrays.asList(TestUtils.buildSleepSession(), TestUtils.buildSleepSession());
+        List<Record> updateRecords = Arrays.asList(buildSleepSession(), buildSleepSession());
 
         // Modify the Uid of the updateRecords to the UUID that was present in the insert records,
         // leaving out alternate records so that they have a new UUID which is not present in the
@@ -371,16 +373,13 @@
     public void testUpdateRecords_recordWithInvalidPackageName_noChangeInDataBase()
             throws InterruptedException {
         List<Record> insertedRecords =
-                TestUtils.insertRecords(
-                        Arrays.asList(
-                                TestUtils.buildSleepSession(), TestUtils.buildSleepSession()));
+                TestUtils.insertRecords(Arrays.asList(buildSleepSession(), buildSleepSession()));
 
         // read inserted records and verify that the data is same as inserted.
         readAndAssertEquals(insertedRecords);
 
         // Generate a second set of records that will be used to perform the update operation.
-        List<Record> updateRecords =
-                Arrays.asList(TestUtils.buildSleepSession(), TestUtils.buildSleepSession());
+        List<Record> updateRecords = Arrays.asList(buildSleepSession(), buildSleepSession());
 
         // Modify the Uuid of the updateRecords to the uuid that was present in the insert records.
         for (int itr = 0; itr < updateRecords.size(); itr++) {
@@ -391,7 +390,7 @@
                             insertedRecords.get(itr).getMetadata().getId(),
                             insertedRecords.get(itr).getMetadata().getClientRecordId()));
             //             adding an entry with invalid packageName.
-            updateRecords.set(itr, TestUtils.buildSleepSession());
+            updateRecords.set(itr, buildSleepSession());
         }
 
         try {
@@ -499,7 +498,7 @@
 
     public static SleepSessionRecord buildSleepSessionMinimal() {
         return new SleepSessionRecord.Builder(
-                        TestUtils.generateMetadata(), SESSION_START_TIME, SESSION_END_TIME)
+                        generateMetadata(), SESSION_START_TIME, SESSION_END_TIME)
                 .build();
     }
 }
diff --git a/tests/cts/src/android/healthconnect/cts/SpeedRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/SpeedRecordTest.java
similarity index 92%
rename from tests/cts/src/android/healthconnect/cts/SpeedRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/SpeedRecordTest.java
index 7677a42..ae79dd2 100644
--- a/tests/cts/src/android/healthconnect/cts/SpeedRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/SpeedRecordTest.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.SpeedRecord.SPEED_AVG;
 import static android.health.connect.datatypes.SpeedRecord.SPEED_MAX;
 import static android.health.connect.datatypes.SpeedRecord.SPEED_MIN;
+import static android.healthconnect.cts.utils.TestUtils.distinctByUuid;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -43,6 +44,7 @@
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.SpeedRecord;
 import android.health.connect.datatypes.units.Velocity;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -52,6 +54,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -72,6 +75,11 @@
     private static final String TAG = "SpeedRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
@@ -553,6 +561,33 @@
         readSpeedRecordUsingIds(insertedRecords);
     }
 
+    @Test
+    public void insertRecords_withDuplicatedClientRecordId_readNoDuplicates() throws Exception {
+        int distinctRecordCount = 10;
+        List<SpeedRecord> records = new ArrayList<>();
+        Instant now = Instant.now();
+        for (int i = 0; i < distinctRecordCount; i++) {
+            SpeedRecord record =
+                    buildRecordForSpeed(
+                            /* speed= */ 10,
+                            /* millisFromStart= */ 0,
+                            /* startTime= */ now.minusMillis(i + 1),
+                            /* endTime= */ now.minusMillis(i),
+                            /* clientRecordId= */ "client_id_" + i);
+
+            records.add(record);
+            records.add(record); // Add each record twice
+        }
+
+        List<Record> insertedRecords = TestUtils.insertRecords(records);
+        assertThat(insertedRecords.size()).isEqualTo(records.size());
+
+        List<Record> distinctRecords = distinctByUuid(insertedRecords);
+        assertThat(distinctRecords.size()).isEqualTo(distinctRecordCount);
+
+        readSpeedRecordUsingIds(distinctRecords);
+    }
+
     SpeedRecord getSpeedRecord_update(Record record, String id, String clientRecordId) {
         Metadata metadata = record.getMetadata();
         Metadata metadataWithId =
@@ -600,6 +635,20 @@
     }
 
     private static SpeedRecord buildRecordForSpeed(double speed, long millisFromStart) {
+        return buildRecordForSpeed(
+                speed,
+                millisFromStart,
+                /* startTime= */ Instant.now(),
+                /* endTime= */ Instant.now().plusMillis(1000),
+                /* clientRecordId= */ "SPR" + Math.random());
+    }
+
+    private static SpeedRecord buildRecordForSpeed(
+            double speed,
+            long millisFromStart,
+            Instant startTime,
+            Instant endTime,
+            String clientRecordId) {
 
         Device device =
                 new Device.Builder()
@@ -611,23 +660,19 @@
                 new DataOrigin.Builder().setPackageName("android.healthconnect.cts").build();
         Metadata.Builder testMetadataBuilder = new Metadata.Builder();
         testMetadataBuilder.setDevice(device).setDataOrigin(dataOrigin);
-        testMetadataBuilder.setClientRecordId("SPR" + Math.random());
+        testMetadataBuilder.setClientRecordId(clientRecordId);
         testMetadataBuilder.setRecordingMethod(Metadata.RECORDING_METHOD_ACTIVELY_RECORDED);
 
         SpeedRecord.SpeedRecordSample speedRecord =
                 new SpeedRecord.SpeedRecordSample(
-                        Velocity.fromMetersPerSecond(speed),
-                        Instant.now().plusMillis(millisFromStart));
+                        Velocity.fromMetersPerSecond(speed), startTime.plusMillis(millisFromStart));
 
         ArrayList<SpeedRecord.SpeedRecordSample> speedRecords = new ArrayList<>();
         speedRecords.add(speedRecord);
         speedRecords.add(speedRecord);
 
         return new SpeedRecord.Builder(
-                        testMetadataBuilder.build(),
-                        Instant.now(),
-                        Instant.now().plusMillis(1000),
-                        speedRecords)
+                        testMetadataBuilder.build(), startTime, endTime, speedRecords)
                 .build();
     }
 }
diff --git a/tests/cts/src/android/healthconnect/cts/StepsCadenceRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/StepsCadenceRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/StepsCadenceRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/StepsCadenceRecordTest.java
index 1465a94..4e69f60 100644
--- a/tests/cts/src/android/healthconnect/cts/StepsCadenceRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/StepsCadenceRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.StepsCadenceRecord.STEPS_CADENCE_RATE_AVG;
 import static android.health.connect.datatypes.StepsCadenceRecord.STEPS_CADENCE_RATE_MAX;
@@ -42,6 +42,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.StepsCadenceRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -51,6 +52,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -72,6 +74,11 @@
 
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/StepsRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/StepsRecordTest.java
similarity index 94%
rename from tests/cts/src/android/healthconnect/cts/StepsRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/StepsRecordTest.java
index 3a99f78..5325fcc 100644
--- a/tests/cts/src/android/healthconnect/cts/StepsRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/StepsRecordTest.java
@@ -14,10 +14,14 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.HealthConnectException.ERROR_INVALID_ARGUMENT;
 import static android.health.connect.datatypes.StepsRecord.STEPS_COUNT_TOTAL;
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
+import static android.healthconnect.cts.utils.DataFactory.getCompleteStepsRecord;
+import static android.healthconnect.cts.utils.DataFactory.getUpdatedStepsRecord;
+import static android.healthconnect.cts.utils.TestUtils.distinctByUuid;
 import static android.healthconnect.cts.utils.TestUtils.readRecordsWithPagination;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -50,6 +54,8 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.StepsRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.DataFactory;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -59,6 +65,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -81,6 +88,11 @@
     private static final String TAG = "StepsRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
@@ -99,7 +111,7 @@
 
     @Test
     public void testInsertStepsRecord() throws InterruptedException {
-        List<Record> records = List.of(getBaseStepsRecord(), TestUtils.getCompleteStepsRecord());
+        List<Record> records = List.of(getBaseStepsRecord(), getCompleteStepsRecord());
         TestUtils.insertRecords(records);
     }
 
@@ -125,11 +137,9 @@
 
     @Test
     public void testReadStepsRecord_usingIds() throws InterruptedException {
-        List<Record> recordList =
-                Arrays.asList(
-                        TestUtils.getCompleteStepsRecord(), TestUtils.getCompleteStepsRecord());
+        List<Record> recordList = Arrays.asList(getCompleteStepsRecord(), getCompleteStepsRecord());
         List<Record> insertedRecords = TestUtils.insertRecords(recordList);
-        readStepsRecordUsingIds(insertedRecords);
+        assertStepsRecordUsingIds(insertedRecords);
     }
 
     @Test
@@ -146,9 +156,7 @@
 
     @Test
     public void testReadStepsRecord_usingClientRecordIds() throws InterruptedException {
-        List<Record> recordList =
-                Arrays.asList(
-                        TestUtils.getCompleteStepsRecord(), TestUtils.getCompleteStepsRecord());
+        List<Record> recordList = Arrays.asList(getCompleteStepsRecord(), getCompleteStepsRecord());
         List<Record> insertedRecords = TestUtils.insertRecords(recordList);
         readStepsRecordUsingClientId(insertedRecords);
     }
@@ -170,7 +178,7 @@
                         new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class)
                                 .setAscending(true)
                                 .build());
-        StepsRecord testRecord = TestUtils.getCompleteStepsRecord();
+        StepsRecord testRecord = getCompleteStepsRecord();
         TestUtils.insertRecords(Collections.singletonList(testRecord));
         List<StepsRecord> newStepsRecords =
                 TestUtils.readRecords(
@@ -188,7 +196,7 @@
                         .setStartTime(Instant.now())
                         .setEndTime(Instant.now().plusMillis(3000))
                         .build();
-        StepsRecord testRecord = TestUtils.getCompleteStepsRecord();
+        StepsRecord testRecord = getCompleteStepsRecord();
         TestUtils.insertRecords(Collections.singletonList(testRecord));
         List<StepsRecord> newStepsRecords =
                 TestUtils.readRecords(
@@ -221,7 +229,7 @@
                                                 .setPackageName(context.getPackageName())
                                                 .build())
                                 .build());
-        StepsRecord testRecord = TestUtils.getCompleteStepsRecord();
+        StepsRecord testRecord = getCompleteStepsRecord();
         TestUtils.insertRecords(Collections.singletonList(testRecord));
         List<StepsRecord> newStepsRecords =
                 TestUtils.readRecords(
@@ -238,7 +246,7 @@
 
     @Test
     public void testReadStepsRecordUsingFilters_dataFilter_incorrect() throws InterruptedException {
-        TestUtils.insertRecords(Collections.singletonList(TestUtils.getCompleteStepsRecord()));
+        TestUtils.insertRecords(Collections.singletonList(getCompleteStepsRecord()));
         ReadRecordsRequestUsingFilters<StepsRecord> requestUsingFilters =
                 new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class)
                         .addDataOrigins(new DataOrigin.Builder().setPackageName("abc").build())
@@ -368,7 +376,7 @@
     @Test
     public void testStepsRecordUsingFilters_nextPageTokenEnd() throws InterruptedException {
         List<Record> recordList =
-                Arrays.asList(TestUtils.getStepsRecord(), TestUtils.getStepsRecord());
+                Arrays.asList(DataFactory.getStepsRecord(), DataFactory.getStepsRecord());
         TestUtils.insertRecords(recordList);
         ReadRecordsResponse<StepsRecord> prevPage =
                 readRecordsWithPagination(
@@ -451,7 +459,7 @@
 
     @Test
     public void testDeleteStepsRecord_no_filters() throws InterruptedException {
-        String id = TestUtils.insertRecordAndGetId(TestUtils.getCompleteStepsRecord());
+        String id = TestUtils.insertRecordAndGetId(getCompleteStepsRecord());
         TestUtils.verifyDeleteRecords(new DeleteUsingFiltersRequest.Builder().build());
         TestUtils.assertRecordNotFound(id, StepsRecord.class);
     }
@@ -463,7 +471,7 @@
                         .setStartTime(Instant.now())
                         .setEndTime(Instant.now().plusMillis(1000))
                         .build();
-        String id = TestUtils.insertRecordAndGetId(TestUtils.getCompleteStepsRecord());
+        String id = TestUtils.insertRecordAndGetId(getCompleteStepsRecord());
         TestUtils.verifyDeleteRecords(
                 new DeleteUsingFiltersRequest.Builder()
                         .addRecordType(StepsRecord.class)
@@ -551,7 +559,7 @@
 
     @Test
     public void testDeleteStepsRecord_recordId_filters() throws InterruptedException {
-        List<Record> records = List.of(getBaseStepsRecord(), TestUtils.getCompleteStepsRecord());
+        List<Record> records = List.of(getBaseStepsRecord(), getCompleteStepsRecord());
         TestUtils.insertRecords(records);
 
         for (Record record : records) {
@@ -566,7 +574,7 @@
     @Test
     public void testDeleteStepsRecord_dataOrigin_filters() throws InterruptedException {
         Context context = ApplicationProvider.getApplicationContext();
-        String id = TestUtils.insertRecordAndGetId(TestUtils.getCompleteStepsRecord());
+        String id = TestUtils.insertRecordAndGetId(getCompleteStepsRecord());
         TestUtils.verifyDeleteRecords(
                 new DeleteUsingFiltersRequest.Builder()
                         .addDataOrigin(
@@ -579,7 +587,7 @@
 
     @Test
     public void testDeleteStepsRecord_dataOrigin_filter_incorrect() throws InterruptedException {
-        String id = TestUtils.insertRecordAndGetId(TestUtils.getCompleteStepsRecord());
+        String id = TestUtils.insertRecordAndGetId(getCompleteStepsRecord());
         TestUtils.verifyDeleteRecords(
                 new DeleteUsingFiltersRequest.Builder()
                         .addDataOrigin(new DataOrigin.Builder().setPackageName("abc").build())
@@ -589,7 +597,7 @@
 
     @Test
     public void testDeleteStepsRecord_usingIds() throws InterruptedException {
-        List<Record> records = List.of(getBaseStepsRecord(), TestUtils.getCompleteStepsRecord());
+        List<Record> records = List.of(getBaseStepsRecord(), getCompleteStepsRecord());
         List<Record> insertedRecord = TestUtils.insertRecords(records);
         List<RecordIdFilter> recordIds = new ArrayList<>(records.size());
         for (Record record : insertedRecord) {
@@ -628,7 +636,7 @@
 
     @Test
     public void testDeleteStepsRecord_usingInvalidClientIds() throws InterruptedException {
-        List<Record> records = List.of(getBaseStepsRecord(), TestUtils.getCompleteStepsRecord());
+        List<Record> records = List.of(getBaseStepsRecord(), getCompleteStepsRecord());
         List<Record> insertedRecord = TestUtils.insertRecords(records);
         List<RecordIdFilter> recordIds = new ArrayList<>(records.size());
         for (Record record : insertedRecord) {
@@ -655,7 +663,7 @@
                         .setStartTime(Instant.now())
                         .setEndTime(Instant.now().plusMillis(1000))
                         .build();
-        String id = TestUtils.insertRecordAndGetId(TestUtils.getCompleteStepsRecord());
+        String id = TestUtils.insertRecordAndGetId(getCompleteStepsRecord());
         TestUtils.verifyDeleteRecords(StepsRecord.class, timeRangeFilter);
         TestUtils.assertRecordNotFound(id, StepsRecord.class);
     }
@@ -699,7 +707,7 @@
     }
 
     @Test
-    public void testAggregation_stepsCountTotal() throws Exception {
+    public void testAggregation_StepsCountTotal() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.ACTIVITY);
         List<Record> records =
                 Arrays.asList(getStepsRecord(1000, 1, 1), getStepsRecord(1000, 2, 1));
@@ -974,23 +982,20 @@
 
         List<Record> insertedRecords =
                 TestUtils.insertRecords(
-                        Arrays.asList(
-                                TestUtils.getCompleteStepsRecord(),
-                                TestUtils.getCompleteStepsRecord()));
+                        Arrays.asList(getCompleteStepsRecord(), getCompleteStepsRecord()));
 
         // read inserted records and verify that the data is same as inserted.
-        readStepsRecordUsingIds(insertedRecords);
+        assertStepsRecordUsingIds(insertedRecords);
 
         // Generate a new set of records that will be used to perform the update operation.
         List<Record> updateRecords =
-                Arrays.asList(
-                        TestUtils.getCompleteStepsRecord(), TestUtils.getCompleteStepsRecord());
+                Arrays.asList(getCompleteStepsRecord(), getCompleteStepsRecord());
 
         // Modify the uid of the updateRecords to the uuid that was present in the insert records.
         for (int itr = 0; itr < updateRecords.size(); itr++) {
             updateRecords.set(
                     itr,
-                    TestUtils.getStepsRecord_update(
+                    getUpdatedStepsRecord(
                             updateRecords.get(itr),
                             insertedRecords.get(itr).getMetadata().getId(),
                             insertedRecords.get(itr).getMetadata().getClientRecordId()));
@@ -999,7 +1004,7 @@
         TestUtils.updateRecords(updateRecords);
 
         // assert the inserted data has been modified by reading the data.
-        readStepsRecordUsingIds(updateRecords);
+        assertStepsRecordUsingIds(updateRecords);
     }
 
     @Test
@@ -1007,17 +1012,14 @@
             throws InterruptedException {
         List<Record> insertedRecords =
                 TestUtils.insertRecords(
-                        Arrays.asList(
-                                TestUtils.getCompleteStepsRecord(),
-                                TestUtils.getCompleteStepsRecord()));
+                        Arrays.asList(getCompleteStepsRecord(), getCompleteStepsRecord()));
 
         // read inserted records and verify that the data is same as inserted.
-        readStepsRecordUsingIds(insertedRecords);
+        assertStepsRecordUsingIds(insertedRecords);
 
         // Generate a second set of records that will be used to perform the update operation.
         List<Record> updateRecords =
-                Arrays.asList(
-                        TestUtils.getCompleteStepsRecord(), TestUtils.getCompleteStepsRecord());
+                Arrays.asList(getCompleteStepsRecord(), getCompleteStepsRecord());
 
         // Modify the Uid of the updateRecords to the UUID that was present in the insert records,
         // leaving out alternate records so that they have a new UUID which is not present in the
@@ -1025,7 +1027,7 @@
         for (int itr = 0; itr < updateRecords.size(); itr++) {
             updateRecords.set(
                     itr,
-                    TestUtils.getStepsRecord_update(
+                    getUpdatedStepsRecord(
                             updateRecords.get(itr),
                             itr % 2 == 0
                                     ? insertedRecords.get(itr).getMetadata().getId()
@@ -1043,7 +1045,7 @@
         }
 
         // assert the inserted data has not been modified by reading the data.
-        readStepsRecordUsingIds(insertedRecords);
+        assertStepsRecordUsingIds(insertedRecords);
     }
 
     @Test
@@ -1051,28 +1053,25 @@
             throws InterruptedException {
         List<Record> insertedRecords =
                 TestUtils.insertRecords(
-                        Arrays.asList(
-                                TestUtils.getCompleteStepsRecord(),
-                                TestUtils.getCompleteStepsRecord()));
+                        Arrays.asList(getCompleteStepsRecord(), getCompleteStepsRecord()));
 
         // read inserted records and verify that the data is same as inserted.
-        readStepsRecordUsingIds(insertedRecords);
+        assertStepsRecordUsingIds(insertedRecords);
 
         // Generate a second set of records that will be used to perform the update operation.
         List<Record> updateRecords =
-                Arrays.asList(
-                        TestUtils.getCompleteStepsRecord(), TestUtils.getCompleteStepsRecord());
+                Arrays.asList(getCompleteStepsRecord(), getCompleteStepsRecord());
 
         // Modify the Uuid of the updateRecords to the uuid that was present in the insert records.
         for (int itr = 0; itr < updateRecords.size(); itr++) {
             updateRecords.set(
                     itr,
-                    TestUtils.getStepsRecord_update(
+                    getUpdatedStepsRecord(
                             updateRecords.get(itr),
                             insertedRecords.get(itr).getMetadata().getId(),
                             insertedRecords.get(itr).getMetadata().getClientRecordId()));
             //             adding an entry with invalid packageName.
-            updateRecords.set(itr, TestUtils.getCompleteStepsRecord());
+            updateRecords.set(itr, getCompleteStepsRecord());
         }
 
         try {
@@ -1084,7 +1083,7 @@
         }
 
         // assert the inserted data has not been modified by reading the data.
-        readStepsRecordUsingIds(insertedRecords);
+        assertStepsRecordUsingIds(insertedRecords);
     }
 
     @Test
@@ -1105,7 +1104,7 @@
         assertThat(response.getUpsertedRecords().size()).isEqualTo(0);
         assertThat(response.getDeletedLogs().size()).isEqualTo(0);
 
-        List<Record> testRecord = Collections.singletonList(TestUtils.getCompleteStepsRecord());
+        List<Record> testRecord = Collections.singletonList(getCompleteStepsRecord());
         TestUtils.insertRecords(testRecord);
         response = TestUtils.getChangeLogs(changeLogsRequest);
         assertThat(response.getUpsertedRecords().size()).isEqualTo(1);
@@ -1312,7 +1311,7 @@
                                 .build(),
                         List.of(
                                 new StepsRecord.Builder(
-                                                TestUtils.generateMetadata(),
+                                                generateMetadata(),
                                                 endTimeInstant.minusSeconds(500),
                                                 endTimeInstant.minusSeconds(100),
                                                 100)
@@ -1320,7 +1319,7 @@
                                         .setEndZoneOffset(ZoneOffset.MIN)
                                         .build(),
                                 new StepsRecord.Builder(
-                                                TestUtils.generateMetadata(),
+                                                generateMetadata(),
                                                 endTimeInstant.minusSeconds(1000),
                                                 endTimeInstant.minusSeconds(800),
                                                 100)
@@ -1483,6 +1482,31 @@
         testAggregateDurationWithLocalTimeForZoneOffset(ZoneOffset.MAX);
     }
 
+    @Test
+    public void insertRecords_withDuplicatedClientRecordId_readNoDuplicates() throws Exception {
+        int distinctRecordCount = 10;
+        List<StepsRecord> records = new ArrayList<>();
+        Instant now = Instant.now();
+        for (int i = 0; i < distinctRecordCount; i++) {
+            StepsRecord record =
+                    getCompleteStepsRecord(
+                            /* startTime= */ now.minusMillis(i + 1),
+                            /* endTime= */ now.minusMillis(i),
+                            /* clientRecordId= */ "client_id_" + i);
+
+            records.add(record);
+            records.add(record); // Add each record twice
+        }
+
+        List<Record> insertedRecords = TestUtils.insertRecords(records);
+        assertThat(insertedRecords.size()).isEqualTo(records.size());
+
+        List<Record> distinctRecords = distinctByUuid(insertedRecords);
+        assertThat(distinctRecords.size()).isEqualTo(distinctRecordCount);
+
+        assertStepsRecordUsingIds(distinctRecords);
+    }
+
     private void testAggregateDurationWithLocalTimeForZoneOffset(ZoneOffset offset)
             throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.ACTIVITY);
@@ -1557,7 +1581,7 @@
                 .build();
     }
 
-    static void readStepsRecordUsingIds(List<Record> recordList) throws InterruptedException {
+    static void assertStepsRecordUsingIds(List<Record> recordList) throws InterruptedException {
         ReadRecordsRequestUsingIds.Builder<StepsRecord> request =
                 new ReadRecordsRequestUsingIds.Builder<>(StepsRecord.class);
         for (Record record : recordList) {
diff --git a/tests/cts/src/android/healthconnect/cts/TotalCaloriesBurnedRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/TotalCaloriesBurnedRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/TotalCaloriesBurnedRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/TotalCaloriesBurnedRecordTest.java
index 9d44665..26c3156 100644
--- a/tests/cts/src/android/healthconnect/cts/TotalCaloriesBurnedRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/TotalCaloriesBurnedRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -39,6 +39,7 @@
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.TotalCaloriesBurnedRecord;
 import android.health.connect.datatypes.units.Energy;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -47,6 +48,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -67,6 +69,11 @@
     private static final String TAG = "TotalCaloriesBurnedRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
@@ -572,7 +579,6 @@
     @Test(expected = UnsupportedOperationException.class)
     public void testAggregation_totalCaloriesBurnt_activeCalories_groupBy() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.ACTIVITY);
-
         Context context = ApplicationProvider.getApplicationContext();
         Instant now = Instant.now();
         TestUtils.getAggregateResponseGroupByPeriod(
@@ -594,7 +600,6 @@
     public void testAggregation_totalCaloriesBurnt_activeCalories_groupBy_duration()
             throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.ACTIVITY);
-
         Context context = ApplicationProvider.getApplicationContext();
         Instant now = Instant.now();
         List<Record> records =
@@ -642,7 +647,6 @@
     public void testAggregation_groupByDurationLocalFilter_shiftRecordsAndFilterWithOffset()
             throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.ACTIVITY);
-
         Context context = ApplicationProvider.getApplicationContext();
         Instant now = Instant.now();
         ZoneOffset offset = ZoneOffset.ofHours(-1);
diff --git a/tests/cts/src/android/healthconnect/cts/Vo2MaxRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/Vo2MaxRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/Vo2MaxRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/Vo2MaxRecordTest.java
index 52af376..588b5e8 100644
--- a/tests/cts/src/android/healthconnect/cts/Vo2MaxRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/Vo2MaxRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -34,6 +34,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.Vo2MaxRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -42,6 +43,7 @@
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -58,6 +60,11 @@
 public class Vo2MaxRecordTest {
     private static final String TAG = "Vo2MaxRecordTest";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @After
     public void tearDown() throws InterruptedException {
         TestUtils.verifyDeleteRecords(
diff --git a/tests/cts/src/android/healthconnect/cts/WeightRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/WeightRecordTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/WeightRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/WeightRecordTest.java
index 06febc4..5f8c993 100644
--- a/tests/cts/src/android/healthconnect/cts/WeightRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/WeightRecordTest.java
@@ -14,11 +14,12 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.WeightRecord.WEIGHT_AVG;
 import static android.health.connect.datatypes.WeightRecord.WEIGHT_MAX;
 import static android.health.connect.datatypes.WeightRecord.WEIGHT_MIN;
+import static android.healthconnect.cts.utils.DataFactory.generateMetadata;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -47,6 +48,7 @@
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.WeightRecord;
 import android.health.connect.datatypes.units.Mass;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
@@ -56,6 +58,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -78,6 +81,11 @@
     private static final String TAG = "WeightRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
@@ -605,7 +613,6 @@
 
     void testAggregatePeriodForZoneOffset(ZoneOffset offset) throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         Instant endTime = Instant.now();
         LocalDateTime endTimeLocal = LocalDateTime.ofInstant(endTime, offset);
         insertThreeWeightRecordsWithZoneOffset(endTime, offset);
@@ -649,6 +656,7 @@
 
     @Test
     public void testAggregateDuration_differentTimeZones_correctBucketTimes() throws Exception {
+        TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
         Context context = ApplicationProvider.getApplicationContext();
         Duration oneHour = Duration.ofHours(1);
         Instant t1 = Instant.now().minus(Duration.ofDays(1)).truncatedTo(ChronoUnit.MILLIS);
@@ -722,7 +730,6 @@
     private void testDurationLocalTimeAggregationZoneOffset(ZoneOffset offset)
             throws InterruptedException {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         Instant endTime = Instant.now();
         LocalDateTime endTimeLocal = LocalDateTime.ofInstant(endTime, offset);
         insertThreeWeightRecordsWithZoneOffset(endTime, offset);
@@ -774,7 +781,6 @@
     @Test
     public void testAggregateLocalFilter_minOffsetRecord() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         LocalDateTime endTimeLocal = LocalDateTime.now(ZoneOffset.UTC);
         Instant endTimeInstant = Instant.now();
 
@@ -791,13 +797,13 @@
                                 .build(),
                         List.of(
                                 new WeightRecord.Builder(
-                                                TestUtils.generateMetadata(),
+                                                generateMetadata(),
                                                 endTimeInstant,
                                                 Mass.fromGrams(10.0))
                                         .setZoneOffset(ZoneOffset.MIN)
                                         .build(),
                                 new WeightRecord.Builder(
-                                                TestUtils.generateMetadata(),
+                                                generateMetadata(),
                                                 endTimeInstant,
                                                 Mass.fromGrams(20.0))
                                         .setZoneOffset(ZoneOffset.MIN)
@@ -822,7 +828,6 @@
 
     private void testOffset(ZoneOffset offset) throws InterruptedException {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         Instant endTimeInstant = Instant.now();
         LocalDateTime endTimeLocal = LocalDateTime.ofInstant(endTimeInstant, offset);
 
@@ -839,13 +844,13 @@
                                 .build(),
                         List.of(
                                 new WeightRecord.Builder(
-                                                TestUtils.generateMetadata(),
+                                                generateMetadata(),
                                                 endTimeInstant,
                                                 Mass.fromGrams(10.0))
                                         .setZoneOffset(offset)
                                         .build(),
                                 new WeightRecord.Builder(
-                                                TestUtils.generateMetadata(),
+                                                generateMetadata(),
                                                 endTimeInstant,
                                                 Mass.fromGrams(20.0))
                                         .setZoneOffset(offset)
@@ -864,13 +869,12 @@
     @Test
     public void testAggregateLocalFilter_daysPeriod() throws Exception {
         TestUtils.setupAggregation(PACKAGE_NAME, HealthDataCategory.BODY_MEASUREMENTS);
-
         LocalDateTime endTimeLocal = LocalDateTime.now(ZoneOffset.UTC);
         Instant endTimeInstant = Instant.now();
         TestUtils.insertRecords(
                 List.of(
                         new WeightRecord.Builder(
-                                        TestUtils.generateMetadata(),
+                                        generateMetadata(),
                                         endTimeInstant.minus(20, DAYS),
                                         Mass.fromGrams(10.0))
                                 .setZoneOffset(ZoneOffset.MIN)
diff --git a/tests/cts/src/android/healthconnect/cts/WheelchairPushesRecordTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/WheelchairPushesRecordTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/WheelchairPushesRecordTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/WheelchairPushesRecordTest.java
index 66efed7..8ee3f0f 100644
--- a/tests/cts/src/android/healthconnect/cts/WheelchairPushesRecordTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/WheelchairPushesRecordTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes;
 
 import static android.health.connect.datatypes.WheelchairPushesRecord.WHEEL_CHAIR_PUSHES_COUNT_TOTAL;
 
@@ -38,6 +38,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.WheelchairPushesRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.core.app.ApplicationProvider;
@@ -46,6 +47,7 @@
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -63,6 +65,11 @@
     private static final String TAG = "WheelchairPushesRecordTest";
     private static final String PACKAGE_NAME = "android.healthconnect.cts";
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
diff --git a/tests/cts/src/android/healthconnect/cts/BloodGlucoseTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/units/BloodGlucoseTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/BloodGlucoseTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/units/BloodGlucoseTest.java
index 7345d31..86c9e26 100644
--- a/tests/cts/src/android/healthconnect/cts/BloodGlucoseTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/units/BloodGlucoseTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes.units;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/cts/src/android/healthconnect/cts/EnergyTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/units/EnergyTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/EnergyTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/units/EnergyTest.java
index cf62000..0a6a6b3 100644
--- a/tests/cts/src/android/healthconnect/cts/EnergyTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/units/EnergyTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes.units;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/cts/src/android/healthconnect/cts/LengthTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/units/LengthTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/LengthTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/units/LengthTest.java
index 9b365f6..165a970 100644
--- a/tests/cts/src/android/healthconnect/cts/LengthTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/units/LengthTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes.units;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/cts/src/android/healthconnect/cts/MassTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/units/MassTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/MassTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/units/MassTest.java
index a268664..cc70763 100644
--- a/tests/cts/src/android/healthconnect/cts/MassTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/units/MassTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes.units;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/cts/src/android/healthconnect/cts/PercentageTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/units/PercentageTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/PercentageTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/units/PercentageTest.java
index 7fcafd0..cf84f23 100644
--- a/tests/cts/src/android/healthconnect/cts/PercentageTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/units/PercentageTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes.units;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/cts/src/android/healthconnect/cts/PowerTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/units/PowerTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/PowerTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/units/PowerTest.java
index 4d89753..33c27bc 100644
--- a/tests/cts/src/android/healthconnect/cts/PowerTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/units/PowerTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes.units;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/cts/src/android/healthconnect/cts/PressureTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/units/PressureTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/PressureTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/units/PressureTest.java
index 286ee86..62dcd57 100644
--- a/tests/cts/src/android/healthconnect/cts/PressureTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/units/PressureTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes.units;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/cts/src/android/healthconnect/cts/TemperatureTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/units/TemperatureTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/TemperatureTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/units/TemperatureTest.java
index e13c9a7..a9b2a78 100644
--- a/tests/cts/src/android/healthconnect/cts/TemperatureTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/units/TemperatureTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes.units;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/cts/src/android/healthconnect/cts/VelocityTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/units/VelocityTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/VelocityTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/units/VelocityTest.java
index c0ae460..98917d1 100644
--- a/tests/cts/src/android/healthconnect/cts/VelocityTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/units/VelocityTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes.units;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/cts/src/android/healthconnect/cts/VolumeTest.java b/tests/cts/src/android/healthconnect/cts/datatypes/units/VolumeTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/VolumeTest.java
rename to tests/cts/src/android/healthconnect/cts/datatypes/units/VolumeTest.java
index f30d5bd..a9fe0a3 100644
--- a/tests/cts/src/android/healthconnect/cts/VolumeTest.java
+++ b/tests/cts/src/android/healthconnect/cts/datatypes/units/VolumeTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.datatypes.units;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/tests/cts/src/android/healthconnect/cts/AppInfoMigrationPayloadTest.java b/tests/cts/src/android/healthconnect/cts/migration/AppInfoMigrationPayloadTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/AppInfoMigrationPayloadTest.java
rename to tests/cts/src/android/healthconnect/cts/migration/AppInfoMigrationPayloadTest.java
index c8abfd7..b8320d8 100644
--- a/tests/cts/src/android/healthconnect/cts/AppInfoMigrationPayloadTest.java
+++ b/tests/cts/src/android/healthconnect/cts/migration/AppInfoMigrationPayloadTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.migration;
 
 import android.health.connect.migration.AppInfoMigrationPayload;
 
diff --git a/tests/cts/src/android/healthconnect/cts/DataMigrationTest.java b/tests/cts/src/android/healthconnect/cts/migration/DataMigrationTest.java
similarity index 99%
rename from tests/cts/src/android/healthconnect/cts/DataMigrationTest.java
rename to tests/cts/src/android/healthconnect/cts/migration/DataMigrationTest.java
index 2bdb49e..22cec71 100644
--- a/tests/cts/src/android/healthconnect/cts/DataMigrationTest.java
+++ b/tests/cts/src/android/healthconnect/cts/migration/DataMigrationTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.migration;
 
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.PackageInfoFlags;
@@ -75,6 +75,7 @@
 import android.health.connect.migration.PermissionMigrationPayload;
 import android.health.connect.migration.PriorityMigrationPayload;
 import android.health.connect.migration.RecordMigrationPayload;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.os.Build;
 import android.os.OutcomeReceiver;
@@ -207,6 +208,11 @@
         }
     }
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() {
         mTargetContext = InstrumentationRegistry.getTargetContext();
diff --git a/tests/cts/src/android/healthconnect/cts/MetadataMigrationPayloadTest.java b/tests/cts/src/android/healthconnect/cts/migration/MetadataMigrationPayloadTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/MetadataMigrationPayloadTest.java
rename to tests/cts/src/android/healthconnect/cts/migration/MetadataMigrationPayloadTest.java
index ebfd744..3b78127 100644
--- a/tests/cts/src/android/healthconnect/cts/MetadataMigrationPayloadTest.java
+++ b/tests/cts/src/android/healthconnect/cts/migration/MetadataMigrationPayloadTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.migration;
 
 import android.health.connect.migration.MetadataMigrationPayload;
 
diff --git a/tests/cts/src/android/healthconnect/cts/MigrationEntityTest.java b/tests/cts/src/android/healthconnect/cts/migration/MigrationEntityTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/MigrationEntityTest.java
rename to tests/cts/src/android/healthconnect/cts/migration/MigrationEntityTest.java
index effeac8..45abeba 100644
--- a/tests/cts/src/android/healthconnect/cts/MigrationEntityTest.java
+++ b/tests/cts/src/android/healthconnect/cts/migration/MigrationEntityTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.migration;
 
 import android.health.connect.migration.AppInfoMigrationPayload;
 import android.health.connect.migration.MigrationEntity;
diff --git a/tests/cts/src/android/healthconnect/cts/MigrationExceptionTest.java b/tests/cts/src/android/healthconnect/cts/migration/MigrationExceptionTest.java
similarity index 96%
rename from tests/cts/src/android/healthconnect/cts/MigrationExceptionTest.java
rename to tests/cts/src/android/healthconnect/cts/migration/MigrationExceptionTest.java
index 0baf9e3..e6de434 100644
--- a/tests/cts/src/android/healthconnect/cts/MigrationExceptionTest.java
+++ b/tests/cts/src/android/healthconnect/cts/migration/MigrationExceptionTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.migration;
 
 import android.health.connect.migration.MigrationException;
 
diff --git a/tests/cts/src/android/healthconnect/cts/PermissionMigrationPayloadTest.java b/tests/cts/src/android/healthconnect/cts/migration/PermissionMigrationPayloadTest.java
similarity index 97%
rename from tests/cts/src/android/healthconnect/cts/PermissionMigrationPayloadTest.java
rename to tests/cts/src/android/healthconnect/cts/migration/PermissionMigrationPayloadTest.java
index a78f0a9..5b816a2 100644
--- a/tests/cts/src/android/healthconnect/cts/PermissionMigrationPayloadTest.java
+++ b/tests/cts/src/android/healthconnect/cts/migration/PermissionMigrationPayloadTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.migration;
 
 import android.health.connect.HealthPermissions;
 import android.health.connect.migration.PermissionMigrationPayload;
diff --git a/tests/cts/src/android/healthconnect/cts/PriorityMigrationPayloadTest.java b/tests/cts/src/android/healthconnect/cts/migration/PriorityMigrationPayloadTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/PriorityMigrationPayloadTest.java
rename to tests/cts/src/android/healthconnect/cts/migration/PriorityMigrationPayloadTest.java
index 678386f..c4989ef 100644
--- a/tests/cts/src/android/healthconnect/cts/PriorityMigrationPayloadTest.java
+++ b/tests/cts/src/android/healthconnect/cts/migration/PriorityMigrationPayloadTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.migration;
 
 import android.health.connect.HealthDataCategory;
 import android.health.connect.datatypes.DataOrigin;
diff --git a/tests/cts/src/android/healthconnect/cts/RecordMigrationPayloadTest.java b/tests/cts/src/android/healthconnect/cts/migration/RecordMigrationPayloadTest.java
similarity index 98%
rename from tests/cts/src/android/healthconnect/cts/RecordMigrationPayloadTest.java
rename to tests/cts/src/android/healthconnect/cts/migration/RecordMigrationPayloadTest.java
index 1b04017..5732e23 100644
--- a/tests/cts/src/android/healthconnect/cts/RecordMigrationPayloadTest.java
+++ b/tests/cts/src/android/healthconnect/cts/migration/RecordMigrationPayloadTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.healthconnect.cts;
+package android.healthconnect.cts.migration;
 
 import android.health.connect.datatypes.Device;
 import android.health.connect.datatypes.Metadata;
diff --git a/tests/cts/src/android/healthconnect/cts/nopermission/HealthConnectManagerNoPermissionsGrantedTest.java b/tests/cts/src/android/healthconnect/cts/nopermission/HealthConnectManagerNoPermissionsGrantedTest.java
index 4056741..fdf329f 100644
--- a/tests/cts/src/android/healthconnect/cts/nopermission/HealthConnectManagerNoPermissionsGrantedTest.java
+++ b/tests/cts/src/android/healthconnect/cts/nopermission/HealthConnectManagerNoPermissionsGrantedTest.java
@@ -18,6 +18,8 @@
 
 import static android.health.connect.datatypes.HeartRateRecord.BPM_MAX;
 import static android.health.connect.datatypes.HeartRateRecord.BPM_MIN;
+import static android.healthconnect.cts.utils.DataFactory.getHeartRateRecord;
+import static android.healthconnect.cts.utils.DataFactory.getTestRecords;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -29,12 +31,14 @@
 import android.health.connect.changelog.ChangeLogTokenRequest;
 import android.health.connect.datatypes.DataOrigin;
 import android.health.connect.datatypes.Record;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Assert;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -52,9 +56,15 @@
 @AppModeFull(reason = "HealthConnectManager is not accessible to instant apps")
 @RunWith(AndroidJUnit4.class)
 public class HealthConnectManagerNoPermissionsGrantedTest {
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Test
     public void testInsertNotAllowed() throws InterruptedException {
-        for (Record testRecord : TestUtils.getTestRecords()) {
+        for (Record testRecord : getTestRecords()) {
             try {
                 TestUtils.insertRecords(Collections.singletonList(testRecord));
                 Assert.fail("Insert must be not allowed without right HC permission");
@@ -67,7 +77,7 @@
 
     @Test
     public void testUpdateNotAllowed() throws InterruptedException {
-        for (Record testRecord : TestUtils.getTestRecords()) {
+        for (Record testRecord : getTestRecords()) {
             try {
                 TestUtils.updateRecords(Collections.singletonList(testRecord));
                 Assert.fail("Update must be not allowed without right HC permission");
@@ -80,7 +90,7 @@
 
     @Test
     public void testDeleteUsingIdNotAllowed() throws InterruptedException {
-        for (Record testRecord : TestUtils.getTestRecords()) {
+        for (Record testRecord : getTestRecords()) {
             try {
                 TestUtils.deleteRecords(Collections.singletonList(testRecord));
                 Assert.fail("Delete using ids must be not allowed without right HC permission");
@@ -93,7 +103,7 @@
 
     @Test
     public void testDeleteUsingFilterNotAllowed() throws InterruptedException {
-        for (Record testRecord : TestUtils.getTestRecords()) {
+        for (Record testRecord : getTestRecords()) {
             try {
                 TestUtils.verifyDeleteRecords(
                         testRecord.getClass(),
@@ -111,7 +121,7 @@
 
     @Test
     public void testChangeLogsTokenNotAllowed() throws InterruptedException {
-        for (Record testRecord : TestUtils.getTestRecords()) {
+        for (Record testRecord : getTestRecords()) {
             try {
                 TestUtils.getChangeLogToken(
                         new ChangeLogTokenRequest.Builder()
@@ -128,7 +138,7 @@
 
     @Test
     public void testReadNotAllowed() throws InterruptedException {
-        for (Record testRecord : TestUtils.getTestRecords()) {
+        for (Record testRecord : getTestRecords()) {
             try {
                 TestUtils.readRecords(
                         new ReadRecordsRequestUsingFilters.Builder<>(testRecord.getClass())
@@ -146,9 +156,7 @@
         try {
             List<Record> records =
                     Arrays.asList(
-                            TestUtils.getHeartRateRecord(71),
-                            TestUtils.getHeartRateRecord(72),
-                            TestUtils.getHeartRateRecord(73));
+                            getHeartRateRecord(71), getHeartRateRecord(72), getHeartRateRecord(73));
             TestUtils.getAggregateResponse(
                     new AggregateRecordsRequest.Builder<Long>(
                                     new TimeInstantRangeFilter.Builder()
diff --git a/tests/cts/src/android/healthconnect/cts/ratelimiter/RateLimiterTest.java b/tests/cts/src/android/healthconnect/cts/ratelimiter/RateLimiterTest.java
index c7a2cdb..ade3176 100644
--- a/tests/cts/src/android/healthconnect/cts/ratelimiter/RateLimiterTest.java
+++ b/tests/cts/src/android/healthconnect/cts/ratelimiter/RateLimiterTest.java
@@ -17,6 +17,9 @@
 package android.healthconnect.cts.ratelimiter;
 
 import static android.health.connect.datatypes.StepsRecord.STEPS_COUNT_TOTAL;
+import static android.healthconnect.cts.utils.DataFactory.buildDevice;
+import static android.healthconnect.cts.utils.DataFactory.getCompleteStepsRecord;
+import static android.healthconnect.cts.utils.DataFactory.getUpdatedStepsRecord;
 
 import static org.hamcrest.CoreMatchers.containsString;
 
@@ -32,8 +35,12 @@
 import android.health.connect.changelog.ChangeLogTokenResponse;
 import android.health.connect.changelog.ChangeLogsRequest;
 import android.health.connect.datatypes.DataOrigin;
+import android.health.connect.datatypes.Device;
+import android.health.connect.datatypes.HeartRateRecord;
+import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.StepsRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.platform.test.annotations.AppModeFull;
 import android.provider.DeviceConfig;
@@ -55,6 +62,7 @@
 import java.time.Duration;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -73,6 +81,11 @@
 
     @Rule public ExpectedException exception = ExpectedException.none();
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws InterruptedException {
         TestUtils.deleteAllStagedRemoteData();
@@ -96,7 +109,7 @@
 
     @Test
     public void testTryAcquireApiCallQuota_readCallsInLimit() throws InterruptedException {
-        List<Record> testRecord = List.of(TestUtils.getCompleteStepsRecord());
+        List<Record> testRecord = List.of(getCompleteStepsRecord());
 
         tryAcquireCallQuotaNTimesForRead(testRecord, TestUtils.insertRecords(testRecord));
     }
@@ -159,17 +172,37 @@
     }
 
     private void exceedChunkMemoryQuota() throws InterruptedException {
-        List<Record> testRecord = Collections.nCopies(30000, TestUtils.getCompleteStepsRecord());
+        List<Record> testRecord = Collections.nCopies(30000, getCompleteStepsRecord());
 
         TestUtils.insertRecords(testRecord);
     }
 
     private void exceedRecordMemoryQuota() throws InterruptedException {
-        TestUtils.insertRecords(List.of(TestUtils.getHugeHeartRateRecord()));
+        Device device = buildDevice();
+        DataOrigin dataOrigin =
+                new DataOrigin.Builder().setPackageName("android.healthconnect.cts").build();
+        Metadata.Builder testMetadataBuilder = new Metadata.Builder();
+        testMetadataBuilder.setDevice(device).setDataOrigin(dataOrigin);
+        testMetadataBuilder.setClientRecordId("HRR" + Math.random());
+        testMetadataBuilder.setRecordingMethod(Metadata.RECORDING_METHOD_ACTIVELY_RECORDED);
+
+        HeartRateRecord.HeartRateSample heartRateRecord =
+                new HeartRateRecord.HeartRateSample(10, Instant.now().plusMillis(100));
+        ArrayList<HeartRateRecord.HeartRateSample> heartRateRecords =
+                new ArrayList<>(Collections.nCopies(85000, heartRateRecord));
+
+        HeartRateRecord testHeartRateRecord =
+                new HeartRateRecord.Builder(
+                                testMetadataBuilder.build(),
+                                Instant.now(),
+                                Instant.now().plusMillis(500),
+                                heartRateRecords)
+                        .build();
+        TestUtils.insertRecords(List.of(testHeartRateRecord));
     }
 
     private void exceedRecordMemoryRollingQuotaBackgroundLimit() throws InterruptedException {
-        List<Record> testRecord = Collections.nCopies(350, TestUtils.getCompleteStepsRecord());
+        List<Record> testRecord = Collections.nCopies(350, getCompleteStepsRecord());
         for (int i = 0; i < 1000; i++) {
             TestUtils.insertRecords(testRecord);
         }
@@ -181,7 +214,7 @@
         Instant endTime = Instant.now();
         float quotaAcquired =
                 getQuotaAcquired(startTime, endTime, WINDOW_15M, MAX_FOREGROUND_WRITE_CALL_15M);
-        List<Record> testRecord = List.of(TestUtils.getCompleteStepsRecord());
+        List<Record> testRecord = List.of(getCompleteStepsRecord());
 
         while (quotaAcquired > 1) {
             TestUtils.insertRecords(testRecord);
@@ -189,7 +222,7 @@
         }
         int tryWriteWithBuffer = 20;
         while (tryWriteWithBuffer > 0) {
-            TestUtils.insertRecords(List.of(TestUtils.getCompleteStepsRecord()));
+            TestUtils.insertRecords(List.of(getCompleteStepsRecord()));
 
             tryWriteWithBuffer--;
         }
@@ -201,7 +234,7 @@
                         .setAscending(true)
                         .build();
         Instant startTime = Instant.now();
-        List<Record> testRecord = Arrays.asList(TestUtils.getCompleteStepsRecord());
+        List<Record> testRecord = Arrays.asList(getCompleteStepsRecord());
 
         List<Record> insertedRecords = TestUtils.insertRecords(testRecord);
         tryAcquireCallQuotaNTimesForRead(testRecord, insertedRecords);
@@ -280,19 +313,19 @@
      * quota is used by MultiAppTestUtils.verifyDeleteRecords.
      */
     private void tryAcquireCallQuotaNTimesForWrite(int nTimes) throws InterruptedException {
-        List<Record> testRecord = Arrays.asList(TestUtils.getCompleteStepsRecord());
+        List<Record> testRecord = Arrays.asList(getCompleteStepsRecord());
 
         List<Record> insertedRecords = List.of();
         for (int i = 0; i < nTimes; i++) {
             if (i % 3 == 0) {
                 insertedRecords = TestUtils.insertRecords(testRecord);
             } else if (i % 3 == 1) {
-                List<Record> updateRecords = Arrays.asList(TestUtils.getCompleteStepsRecord());
+                List<Record> updateRecords = Arrays.asList(getCompleteStepsRecord());
 
                 for (int itr = 0; itr < updateRecords.size(); itr++) {
                     updateRecords.set(
                             itr,
-                            TestUtils.getStepsRecord_update(
+                            getUpdatedStepsRecord(
                                     updateRecords.get(itr),
                                     insertedRecords.get(itr).getMetadata().getId(),
                                     insertedRecords.get(itr).getMetadata().getClientRecordId()));
diff --git a/tests/cts/src/android/healthconnect/cts/readdata/PaginationTests.java b/tests/cts/src/android/healthconnect/cts/readdata/PaginationTests.java
new file mode 100644
index 0000000..dfb10b4
--- /dev/null
+++ b/tests/cts/src/android/healthconnect/cts/readdata/PaginationTests.java
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2024 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 android.healthconnect.cts.readdata;
+
+import static android.healthconnect.cts.utils.DataFactory.getDistanceRecord;
+import static android.healthconnect.cts.utils.DataFactory.getHeartRateRecord;
+import static android.healthconnect.cts.utils.DataFactory.getStepsRecord;
+import static android.healthconnect.cts.utils.DataFactory.getTotalCaloriesBurnedRecord;
+import static android.healthconnect.cts.utils.TestUtils.getReadRecordsResponse;
+import static android.healthconnect.cts.utils.TestUtils.insertRecords;
+import static android.healthconnect.cts.utils.TestUtils.readRecords;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+import static java.time.temporal.ChronoUnit.MINUTES;
+
+import android.health.connect.ReadRecordsRequest;
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.ReadRecordsResponse;
+import android.health.connect.datatypes.DistanceRecord;
+import android.health.connect.datatypes.HeartRateRecord;
+import android.health.connect.datatypes.Record;
+import android.health.connect.datatypes.StepsRecord;
+import android.health.connect.datatypes.TotalCaloriesBurnedRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
+
+import com.google.common.collect.ImmutableList;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.time.Instant;
+import java.util.List;
+
+public class PaginationTests {
+    private static final int MINIMUM_PAGE_SIZE = 1;
+    private static final int MAXIMUM_PAGE_SIZE = 5000;
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
+    @Before
+    public void setup() {
+        TestUtils.deleteAllStagedRemoteData();
+    }
+
+    @After
+    public void tearDown() {
+        TestUtils.deleteAllStagedRemoteData();
+    }
+
+    @Test
+    public void readAllData_moreThanOnePage_allPagesReturnedCorrectly() throws Exception {
+        Instant startTime = Instant.now().minus(1, DAYS);
+        insertRecords(
+                List.of(
+                        getDistanceRecord(
+                                4.0,
+                                startTime.plus(40, MINUTES),
+                                startTime.plus(50, MINUTES),
+                                "id4"),
+                        getDistanceRecord(1.0, startTime, startTime.plus(5, MINUTES), "id1"),
+                        getDistanceRecord(
+                                10.0,
+                                startTime.plus(25, MINUTES),
+                                startTime.plus(30, MINUTES),
+                                "id3"),
+                        getDistanceRecord(
+                                5.0,
+                                startTime.plus(5, MINUTES),
+                                startTime.plus(15, MINUTES),
+                                "id2"),
+                        getDistanceRecord(
+                                2.0,
+                                startTime.plus(55, MINUTES),
+                                startTime.plus(60, MINUTES),
+                                "id5")));
+
+        ReadRecordsRequest<DistanceRecord> request1 =
+                new ReadRecordsRequestUsingFilters.Builder<>(DistanceRecord.class)
+                        .setPageSize(2)
+                        .setAscending(false)
+                        .build();
+        ReadRecordsResponse<DistanceRecord> page1 = getReadRecordsResponse(request1);
+        assertThat(page1.getRecords()).hasSize(2);
+        assertClientId(page1.getRecords().get(0), "id5");
+        assertClientId(page1.getRecords().get(1), "id4");
+        assertThat(page1.getNextPageToken()).isNotEqualTo(-1);
+
+        ReadRecordsRequest<DistanceRecord> request2 =
+                new ReadRecordsRequestUsingFilters.Builder<>(DistanceRecord.class)
+                        .setPageSize(2)
+                        .setPageToken(page1.getNextPageToken())
+                        .build();
+        ReadRecordsResponse<DistanceRecord> page2 = getReadRecordsResponse(request2);
+        assertThat(page2.getRecords()).hasSize(2);
+        assertClientId(page2.getRecords().get(0), "id3");
+        assertClientId(page2.getRecords().get(1), "id2");
+        assertThat(page2.getNextPageToken()).isNotEqualTo(-1);
+
+        ReadRecordsRequest<DistanceRecord> request3 =
+                new ReadRecordsRequestUsingFilters.Builder<>(DistanceRecord.class)
+                        .setPageSize(2)
+                        .setPageToken(page2.getNextPageToken())
+                        .build();
+        ReadRecordsResponse<DistanceRecord> page3 = getReadRecordsResponse(request3);
+        assertThat(page3.getRecords()).hasSize(1);
+        assertClientId(page3.getRecords().get(0), "id1");
+        assertThat(page3.getNextPageToken()).isEqualTo(-1);
+    }
+
+    @Test
+    public void readAllData_multiplePagesSameStartTimeRecords_paginatedCorrectly()
+            throws Exception {
+        Instant startTime = Instant.now().minus(1, DAYS);
+
+        insertRecords(
+                List.of(
+                        getStepsRecord(100, startTime, startTime.plusSeconds(500), "id1"),
+                        getStepsRecord(100, startTime, startTime.plusSeconds(200), "id2"),
+                        getStepsRecord(100, startTime, startTime.plusSeconds(400), "id3"),
+                        getStepsRecord(100, startTime, startTime.plusSeconds(300), "id4")));
+
+        ReadRecordsRequest<StepsRecord> request1 =
+                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class)
+                        .setPageSize(2)
+                        .build();
+        ReadRecordsResponse<StepsRecord> page1 = getReadRecordsResponse(request1);
+        assertThat(page1.getRecords()).hasSize(2);
+        assertClientId(page1.getRecords().get(0), "id1");
+        assertClientId(page1.getRecords().get(1), "id2");
+
+        ReadRecordsRequest<StepsRecord> request2 =
+                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class)
+                        .setPageSize(2)
+                        .setPageToken(page1.getNextPageToken())
+                        .build();
+        ReadRecordsResponse<StepsRecord> page2 = getReadRecordsResponse(request2);
+        assertThat(page2.getRecords()).hasSize(2);
+        assertClientId(page2.getRecords().get(0), "id3");
+        assertClientId(page2.getRecords().get(1), "id4");
+        assertThat(page2.getNextPageToken()).isEqualTo(-1);
+    }
+
+    @Test
+    public void readOnePage_pageTokenSpecified_returnsCorrectPage() throws Exception {
+        Instant now = Instant.now();
+        insertRecords(
+                List.of(
+                        getHeartRateRecord(60, now.minusMillis(5000), "id1"),
+                        getHeartRateRecord(70, now.minusMillis(4000), "id2"),
+                        getHeartRateRecord(80, now.minusMillis(3000), "id3")));
+
+        ReadRecordsRequest<HeartRateRecord> request1 =
+                new ReadRecordsRequestUsingFilters.Builder<>(HeartRateRecord.class)
+                        .setPageSize(1)
+                        .build();
+        ReadRecordsResponse<HeartRateRecord> page1 = getReadRecordsResponse(request1);
+
+        ReadRecordsRequest<HeartRateRecord> request2 =
+                new ReadRecordsRequestUsingFilters.Builder<>(HeartRateRecord.class)
+                        .setPageSize(1)
+                        .setPageToken(page1.getNextPageToken())
+                        .build();
+        ReadRecordsResponse<HeartRateRecord> page2 = getReadRecordsResponse(request2);
+        String expectedId = page2.getRecords().get(0).getMetadata().getClientRecordId();
+
+        ReadRecordsRequest<HeartRateRecord> request3 =
+                new ReadRecordsRequestUsingFilters.Builder<>(HeartRateRecord.class)
+                        .setPageSize(1)
+                        .setPageToken(page2.getNextPageToken())
+                        .build();
+        ReadRecordsResponse<HeartRateRecord> page3 = getReadRecordsResponse(request3);
+        assertThat(page3.getNextPageToken()).isEqualTo(-1);
+
+        // Read page2 again with page1 page token, see if the correct record is returned
+        ReadRecordsRequest<HeartRateRecord> request =
+                new ReadRecordsRequestUsingFilters.Builder<>(HeartRateRecord.class)
+                        .setPageSize(1)
+                        .setPageToken(page1.getNextPageToken())
+                        .build();
+        assertClientId(readRecords(request).get(0), expectedId);
+    }
+
+    @Test
+    public void readOnePage_pageSizeNotSet_defaultPageSizeUsed() throws Exception {
+        ImmutableList.Builder<TotalCaloriesBurnedRecord> builder = new ImmutableList.Builder<>();
+        for (int i = 0; i < 1001; i++) {
+            builder.add(getTotalCaloriesBurnedRecord("id" + i));
+        }
+        insertRecords(builder.build());
+        ReadRecordsRequest<TotalCaloriesBurnedRecord> request =
+                new ReadRecordsRequestUsingFilters.Builder<>(TotalCaloriesBurnedRecord.class)
+                        .build();
+        ReadRecordsResponse<TotalCaloriesBurnedRecord> response = getReadRecordsResponse(request);
+        assertThat(response.getRecords()).hasSize(1000);
+        assertThat(response.getNextPageToken()).isNotEqualTo(-1);
+    }
+
+    @Test
+    public void readRequest_pageSizeOutOfRange_throws() {
+        ReadRecordsRequestUsingFilters.Builder<StepsRecord> request =
+                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class);
+
+        Throwable thrown =
+                assertThrows(
+                        IllegalArgumentException.class,
+                        () -> request.setPageSize(MAXIMUM_PAGE_SIZE + 1));
+        assertThat(thrown.getMessage()).contains("Valid pageSize range is");
+        thrown =
+                assertThrows(
+                        IllegalArgumentException.class,
+                        () -> request.setPageSize(MINIMUM_PAGE_SIZE - 1));
+        assertThat(thrown.getMessage()).contains("Valid pageSize range is");
+    }
+
+    private static void assertClientId(Record record, String expected) {
+        assertThat(record.getMetadata().getClientRecordId()).isEqualTo(expected);
+    }
+}
diff --git a/tests/cts/src/android/healthconnect/cts/readdata/ReadByFilterTests.java b/tests/cts/src/android/healthconnect/cts/readdata/ReadByFilterTests.java
new file mode 100644
index 0000000..02b8c47
--- /dev/null
+++ b/tests/cts/src/android/healthconnect/cts/readdata/ReadByFilterTests.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2024 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 android.healthconnect.cts.readdata;
+
+import static android.healthconnect.cts.utils.DataFactory.getDataOrigin;
+import static android.healthconnect.cts.utils.DataFactory.getDistanceRecord;
+import static android.healthconnect.cts.utils.DataFactory.getHeartRateRecord;
+import static android.healthconnect.cts.utils.DataFactory.getStepsRecord;
+import static android.healthconnect.cts.utils.DataFactory.getTotalCaloriesBurnedRecord;
+import static android.healthconnect.cts.utils.TestUtils.PKG_TEST_APP;
+import static android.healthconnect.cts.utils.TestUtils.insertRecords;
+import static android.healthconnect.cts.utils.TestUtils.insertStepsRecordViaTestApp;
+import static android.healthconnect.cts.utils.TestUtils.readRecords;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static java.time.temporal.ChronoUnit.DAYS;
+
+import android.content.Context;
+import android.health.connect.ReadRecordsRequest;
+import android.health.connect.ReadRecordsRequestUsingFilters;
+import android.health.connect.datatypes.DistanceRecord;
+import android.health.connect.datatypes.HeartRateRecord;
+import android.health.connect.datatypes.Record;
+import android.health.connect.datatypes.StepsRecord;
+import android.health.connect.datatypes.TotalCaloriesBurnedRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.time.Instant;
+import java.util.List;
+
+public class ReadByFilterTests {
+    private Context mContext;
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
+    @Before
+    public void setup() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        TestUtils.deleteAllStagedRemoteData();
+    }
+
+    @After
+    public void tearDown() {
+        TestUtils.deleteAllStagedRemoteData();
+    }
+
+    @Test
+    public void filterByDataType_dataOfOtherTypesExcluded() throws Exception {
+        String distanceId = "distanceRecord";
+        String stepsId = "stepsRecord";
+        String heartRateId = "heartRateRecord";
+        String caloriesId = "totalCaloriesRecord";
+        Instant startTime = Instant.now().minus(1, DAYS);
+        insertRecords(
+                List.of(
+                        getDistanceRecord(123.0, startTime, startTime.plusMillis(1000), distanceId),
+                        getStepsRecord(100, stepsId),
+                        getHeartRateRecord(72, heartRateId),
+                        getTotalCaloriesBurnedRecord(caloriesId)));
+
+        ReadRecordsRequest<DistanceRecord> distanceRequest =
+                new ReadRecordsRequestUsingFilters.Builder<>(DistanceRecord.class).build();
+        List<DistanceRecord> distanceRecords = readRecords(distanceRequest);
+        assertThat(distanceRecords).hasSize(1);
+        assertClientId(distanceRecords.get(0), distanceId);
+
+        ReadRecordsRequest<StepsRecord> stepsRequest =
+                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class).build();
+        List<StepsRecord> stepsRecords = readRecords(stepsRequest);
+        assertThat(stepsRecords).hasSize(1);
+        assertClientId(stepsRecords.get(0), stepsId);
+
+        ReadRecordsRequest<HeartRateRecord> heartRateRequest =
+                new ReadRecordsRequestUsingFilters.Builder<>(HeartRateRecord.class).build();
+        List<HeartRateRecord> heartRateRecords = readRecords(heartRateRequest);
+        assertThat(heartRateRecords).hasSize(1);
+        assertClientId(heartRateRecords.get(0), heartRateId);
+
+        ReadRecordsRequest<TotalCaloriesBurnedRecord> caloriesRequest =
+                new ReadRecordsRequestUsingFilters.Builder<>(TotalCaloriesBurnedRecord.class)
+                        .build();
+        List<TotalCaloriesBurnedRecord> caloriesRecords = readRecords(caloriesRequest);
+        assertThat(caloriesRecords).hasSize(1);
+        assertClientId(caloriesRecords.get(0), caloriesId);
+    }
+
+    @Test
+    public void filterByDataOrigin_dataOfOtherOriginsExcluded() throws Exception {
+        Instant startTime = Instant.now().minus(1, DAYS);
+        String id =
+                insertStepsRecordViaTestApp(mContext, startTime, startTime.plusMillis(1000), 50)
+                        .get(0);
+        insertRecords(
+                List.of(
+                        getStepsRecord(
+                                100,
+                                startTime.plusMillis(1000),
+                                startTime.plusMillis(2000),
+                                "own_steps")));
+
+        ReadRecordsRequest<StepsRecord> ownDataRequest =
+                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class)
+                        .addDataOrigins(getDataOrigin(mContext.getPackageName()))
+                        .build();
+        List<StepsRecord> stepsRecords = readRecords(ownDataRequest);
+        assertThat(stepsRecords).hasSize(1);
+        assertClientId(stepsRecords.get(0), "own_steps");
+
+        ReadRecordsRequest<StepsRecord> testAppDataRequest =
+                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class)
+                        .addDataOrigins(getDataOrigin(PKG_TEST_APP))
+                        .build();
+        stepsRecords = readRecords(testAppDataRequest);
+        assertThat(stepsRecords).hasSize(1);
+        assertThat(stepsRecords.get(0).getMetadata().getId()).isEqualTo(id);
+    }
+
+    @Test
+    public void filterByDataOrigin_noFilterSet_allDataReturned() throws Exception {
+        Instant startTime = Instant.now().minus(1, DAYS);
+        insertStepsRecordViaTestApp(mContext, startTime, startTime.plusMillis(1000), 50);
+        insertRecords(
+                List.of(
+                        getStepsRecord(
+                                100,
+                                startTime.plusMillis(1000),
+                                startTime.plusMillis(2000),
+                                "own_steps")));
+
+        ReadRecordsRequest<StepsRecord> request =
+                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class).build();
+        assertThat(readRecords(request)).hasSize(2);
+    }
+
+    @Test
+    public void filterByDataOrigin_invalidOrigin_emptyResult() throws Exception {
+        insertRecords(List.of(getStepsRecord()));
+
+        ReadRecordsRequest<StepsRecord> allDataRequest =
+                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class).build();
+        assertThat(readRecords(allDataRequest)).hasSize(1);
+
+        ReadRecordsRequest<StepsRecord> invalidOriginRequest =
+                new ReadRecordsRequestUsingFilters.Builder<>(StepsRecord.class)
+                        .addDataOrigins(getDataOrigin("invalid.app"))
+                        .build();
+        List<StepsRecord> stepsRecords = readRecords(invalidOriginRequest);
+        assertThat(stepsRecords).isEmpty();
+    }
+
+    private static void assertClientId(Record record, String expected) {
+        assertThat(record.getMetadata().getClientRecordId()).isEqualTo(expected);
+    }
+}
diff --git a/tests/cts/src/android/healthconnect/cts/readdata/ReadByIdTests.java b/tests/cts/src/android/healthconnect/cts/readdata/ReadByIdTests.java
new file mode 100644
index 0000000..aaa5242
--- /dev/null
+++ b/tests/cts/src/android/healthconnect/cts/readdata/ReadByIdTests.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2024 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 android.healthconnect.cts.readdata;
+
+import static android.healthconnect.cts.utils.DataFactory.getDistanceRecord;
+import static android.healthconnect.cts.utils.DataFactory.getTotalCaloriesBurnedRecord;
+import static android.healthconnect.cts.utils.TestUtils.getReadRecordsResponse;
+import static android.healthconnect.cts.utils.TestUtils.insertRecords;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.health.connect.ReadRecordsRequestUsingIds;
+import android.health.connect.ReadRecordsResponse;
+import android.health.connect.datatypes.BasalMetabolicRateRecord;
+import android.health.connect.datatypes.DistanceRecord;
+import android.health.connect.datatypes.Record;
+import android.health.connect.datatypes.SleepSessionRecord;
+import android.health.connect.datatypes.StepsRecord;
+import android.health.connect.datatypes.TotalCaloriesBurnedRecord;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+import java.util.List;
+
+public class ReadByIdTests {
+    private static final int MAX_RECORD_NUM_PER_REQUEST = 5000;
+
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
+    @Before
+    public void setup() {
+        TestUtils.deleteAllStagedRemoteData();
+    }
+
+    @After
+    public void tearDown() {
+        TestUtils.deleteAllStagedRemoteData();
+    }
+
+    @Test
+    public void readDataById_noPageTokenSet() throws Exception {
+        List<Record> records = insertRecords(List.of(getDistanceRecord()));
+        String uuid = records.get(0).getMetadata().getId();
+        ReadRecordsRequestUsingIds<DistanceRecord> request =
+                new ReadRecordsRequestUsingIds.Builder<>(DistanceRecord.class).addId(uuid).build();
+        ReadRecordsResponse<?> response = getReadRecordsResponse(request);
+        assertThat(response.getRecords()).isNotEmpty();
+        assertThat(response.getNextPageToken()).isEqualTo(-1);
+    }
+
+    @Test
+    public void readDataByClientId_noPageTokenSet() throws Exception {
+        String clientId = "calories";
+        insertRecords(List.of(getTotalCaloriesBurnedRecord(clientId)));
+        ReadRecordsRequestUsingIds<TotalCaloriesBurnedRecord> request =
+                new ReadRecordsRequestUsingIds.Builder<>(TotalCaloriesBurnedRecord.class)
+                        .addClientRecordId(clientId)
+                        .build();
+
+        ReadRecordsResponse<?> response = getReadRecordsResponse(request);
+        assertThat(response.getRecords()).isNotEmpty();
+        assertThat(response.getNextPageToken()).isEqualTo(-1);
+    }
+
+    @Test
+    public void readDataByEmptyId_throws() {
+        ReadRecordsRequestUsingIds.Builder<BasalMetabolicRateRecord> requestBuilder =
+                new ReadRecordsRequestUsingIds.Builder<>(BasalMetabolicRateRecord.class);
+        Throwable thrown = assertThrows(IllegalArgumentException.class, requestBuilder::build);
+        assertThat(thrown).hasMessageThat().contains("RecordIdFilter list is empty");
+    }
+
+    @Test
+    public void readDataById_nullId_throws() {
+        ReadRecordsRequestUsingIds.Builder<SleepSessionRecord> requestBuilder =
+                new ReadRecordsRequestUsingIds.Builder<>(SleepSessionRecord.class);
+
+        assertThrows(NullPointerException.class, () -> requestBuilder.addId(null));
+        assertThrows(NullPointerException.class, () -> requestBuilder.addClientRecordId(null));
+    }
+
+    @Test
+    public void readDataById_maxPageSizeExceeded_throws() {
+        ReadRecordsRequestUsingIds.Builder<StepsRecord> request =
+                new ReadRecordsRequestUsingIds.Builder<>(StepsRecord.class);
+        for (int i = 0; i < MAX_RECORD_NUM_PER_REQUEST; i++) {
+            request.addClientRecordId("client.id" + i);
+        }
+        Throwable thrown =
+                assertThrows(IllegalArgumentException.class, () -> request.addId("extra_id"));
+        assertThat(thrown).hasMessageThat().contains("Maximum allowed pageSize is 5000");
+        thrown =
+                assertThrows(
+                        IllegalArgumentException.class,
+                        () -> request.addClientRecordId("extra_client_id"));
+        assertThat(thrown).hasMessageThat().contains("Maximum allowed pageSize is 5000");
+    }
+}
diff --git a/tests/cts/src/android/healthconnect/cts/showmigrationinfointent/ShowMigrationInfoIntentAbsentTest.java b/tests/cts/src/android/healthconnect/cts/showmigrationinfointent/ShowMigrationInfoIntentAbsentTest.java
index 1f1ceaa..a7c94b5 100644
--- a/tests/cts/src/android/healthconnect/cts/showmigrationinfointent/ShowMigrationInfoIntentAbsentTest.java
+++ b/tests/cts/src/android/healthconnect/cts/showmigrationinfointent/ShowMigrationInfoIntentAbsentTest.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.health.connect.HealthConnectManager;
 import android.health.connect.migration.MigrationException;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestUtils;
 import android.os.Build;
 import android.os.OutcomeReceiver;
@@ -35,6 +36,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -51,6 +53,11 @@
     private HealthConnectManager mManager;
     UiAutomation uiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() {
         mContext = InstrumentationRegistry.getInstrumentation().getContext();
diff --git a/tests/cts/src/android/healthconnect/cts/ui/CategoriesFragmentTest.kt b/tests/cts/src/android/healthconnect/cts/ui/CategoriesFragmentTest.kt
index 90ca2f5..2b7dba5 100644
--- a/tests/cts/src/android/healthconnect/cts/ui/CategoriesFragmentTest.kt
+++ b/tests/cts/src/android/healthconnect/cts/ui/CategoriesFragmentTest.kt
@@ -23,6 +23,7 @@
 import android.healthconnect.cts.lib.UiTestUtils.clickOnText
 import android.healthconnect.cts.lib.UiTestUtils.stepsRecordFromTestApp
 import android.healthconnect.cts.lib.UiTestUtils.waitDisplayed
+import android.healthconnect.cts.utils.TestUtils
 import android.healthconnect.cts.utils.TestUtils.insertRecords
 import android.healthconnect.cts.utils.TestUtils.verifyDeleteRecords
 import androidx.test.uiautomator.By
@@ -39,6 +40,9 @@
         @JvmStatic
         @BeforeClass
         fun setup() {
+            if (!TestUtils.isHardwareSupported()) {
+                return
+            }
             val records: List<Record> = listOf(stepsRecordFromTestApp(), stepsRecordFromTestApp())
             insertRecords(records)
         }
@@ -46,6 +50,9 @@
         @JvmStatic
         @AfterClass
         fun teardown() {
+            if (!TestUtils.isHardwareSupported()) {
+                return
+            }
             verifyDeleteRecords(
                 StepsRecord::class.java,
                 TimeInstantRangeFilter.Builder()
diff --git a/tests/cts/src/android/healthconnect/cts/ui/DataAccessFragmentTest.kt b/tests/cts/src/android/healthconnect/cts/ui/DataAccessFragmentTest.kt
index dbe0665..7c87eb1 100644
--- a/tests/cts/src/android/healthconnect/cts/ui/DataAccessFragmentTest.kt
+++ b/tests/cts/src/android/healthconnect/cts/ui/DataAccessFragmentTest.kt
@@ -17,12 +17,13 @@
 
 import android.health.connect.TimeInstantRangeFilter
 import android.health.connect.datatypes.StepsRecord
-import android.healthconnect.cts.utils.TestUtils.insertRecords
-import android.healthconnect.cts.utils.TestUtils.verifyDeleteRecords
 import android.healthconnect.cts.lib.ActivityLauncher.launchDataActivity
 import android.healthconnect.cts.lib.UiTestUtils.clickOnText
 import android.healthconnect.cts.lib.UiTestUtils.stepsRecordFromTestApp
 import android.healthconnect.cts.lib.UiTestUtils.waitDisplayed
+import android.healthconnect.cts.utils.TestUtils
+import android.healthconnect.cts.utils.TestUtils.insertRecords
+import android.healthconnect.cts.utils.TestUtils.verifyDeleteRecords
 import androidx.test.uiautomator.By
 import java.time.Duration
 import java.time.Instant
@@ -38,6 +39,9 @@
         @JvmStatic
         @AfterClass
         fun tearDown() {
+            if (!TestUtils.isHardwareSupported()) {
+                return
+            }
             verifyDeleteRecords(
                 StepsRecord::class.java,
                 TimeInstantRangeFilter.Builder()
diff --git a/tests/cts/src/android/healthconnect/cts/ui/DataEntriesFragmentTest.kt b/tests/cts/src/android/healthconnect/cts/ui/DataEntriesFragmentTest.kt
index 783393f..a14b1dd 100644
--- a/tests/cts/src/android/healthconnect/cts/ui/DataEntriesFragmentTest.kt
+++ b/tests/cts/src/android/healthconnect/cts/ui/DataEntriesFragmentTest.kt
@@ -18,12 +18,13 @@
 import android.health.connect.TimeInstantRangeFilter
 import android.health.connect.datatypes.DistanceRecord
 import android.health.connect.datatypes.StepsRecord
-import android.healthconnect.cts.utils.TestUtils.insertRecords
-import android.healthconnect.cts.utils.TestUtils.verifyDeleteRecords
 import android.healthconnect.cts.lib.ActivityLauncher.launchDataActivity
 import android.healthconnect.cts.lib.UiTestUtils.clickOnText
 import android.healthconnect.cts.lib.UiTestUtils.distanceRecordFromTestApp
 import android.healthconnect.cts.lib.UiTestUtils.stepsRecordFromTestApp
+import android.healthconnect.cts.utils.TestUtils
+import android.healthconnect.cts.utils.TestUtils.insertRecords
+import android.healthconnect.cts.utils.TestUtils.verifyDeleteRecords
 import java.time.Instant
 import java.time.Period.ofDays
 import org.junit.AfterClass
@@ -38,6 +39,9 @@
         @JvmStatic
         @AfterClass
         fun tearDown() {
+            if (!TestUtils.isHardwareSupported()) {
+                return
+            }
             verifyDeleteRecords(
                 StepsRecord::class.java,
                 TimeInstantRangeFilter.Builder()
diff --git a/tests/cts/src/android/healthconnect/cts/ui/ExerciseRouteRequestTest.kt b/tests/cts/src/android/healthconnect/cts/ui/ExerciseRouteRequestTest.kt
new file mode 100644
index 0000000..bf6a4cd
--- /dev/null
+++ b/tests/cts/src/android/healthconnect/cts/ui/ExerciseRouteRequestTest.kt
@@ -0,0 +1,397 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts.ui
+
+import android.app.Activity
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.health.connect.HealthConnectManager.ACTION_REQUEST_EXERCISE_ROUTE
+import android.health.connect.HealthConnectManager.EXTRA_EXERCISE_ROUTE
+import android.health.connect.HealthConnectManager.EXTRA_SESSION_ID
+import android.health.connect.HealthPermissions
+import android.health.connect.TimeInstantRangeFilter
+import android.health.connect.datatypes.ExerciseRoute
+import android.health.connect.datatypes.ExerciseSessionRecord
+import android.health.connect.datatypes.ExerciseSessionType
+import android.healthconnect.cts.lib.TestAppProxy
+import android.healthconnect.cts.lib.UiTestUtils.clickOnText
+import android.healthconnect.cts.lib.UiTestUtils.scrollDownTo
+import android.healthconnect.cts.lib.UiTestUtils.waitDisplayed
+import android.healthconnect.cts.lib.UiTestUtils.waitNotDisplayed
+import android.healthconnect.cts.utils.DataFactory.getEmptyMetadata
+import android.healthconnect.cts.utils.PermissionHelper.READ_EXERCISE_ROUTES
+import android.healthconnect.cts.utils.PermissionHelper.getDeclaredHealthPermissions
+import android.healthconnect.cts.utils.PermissionHelper.grantPermission
+import android.healthconnect.cts.utils.PermissionHelper.runWithDeviceConfigForController
+import android.healthconnect.cts.utils.PermissionHelper.runWithRevokedPermission
+import android.healthconnect.cts.utils.PermissionHelper.runWithUserFixedPermission
+import android.healthconnect.cts.utils.ProxyActivity
+import android.healthconnect.cts.utils.RevokedHealthPermissionRule
+import android.healthconnect.cts.utils.TestUtils
+import android.healthconnect.cts.utils.TestUtils.insertRecordAndGetId
+import androidx.test.uiautomator.By
+import com.google.common.truth.Truth.assertThat
+import java.time.Duration
+import java.time.Instant
+import org.junit.AfterClass
+import org.junit.Assert.assertThrows
+import org.junit.Rule
+import org.junit.Test
+
+class ExerciseRouteRequestTest : HealthConnectBaseTest() {
+
+    companion object {
+        private const val READ_ROUTES_ALL_FEATURE_FLAG = "exercise_routes_read_all_enable"
+        private val ROUTE_READER_WRITER_APP =
+            TestAppProxy.forPackageName("android.healthconnect.cts.testapp.readWritePerms.A")
+
+        @JvmStatic
+        @AfterClass
+        fun tearDown() {
+            TestUtils.verifyDeleteRecords(
+                ExerciseSessionRecord::class.java,
+                TimeInstantRangeFilter.Builder()
+                    .setStartTime(Instant.EPOCH)
+                    .setEndTime(Instant.now())
+                    .build())
+        }
+    }
+
+    @JvmField
+    @Rule
+    public val revokedPermissionRule =
+        RevokedHealthPermissionRule(ROUTE_READER_WRITER_APP.getPackageName(), READ_EXERCISE_ROUTES)
+
+    @Test
+    fun requestRoute_showsDialog_clickAllowThis_returnsRoute_permissionRemainsRevoked() {
+        val record = getExerciseSessionWithRoute()
+        val recordId = insertRecordAndGetId(record)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+
+        val result =
+            ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent) {
+                waitDisplayed(By.text("Allow all routes"))
+                scrollDownTo(By.text("Don't allow"))
+                clickOnText("Allow this route")
+            }
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_OK)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_EXERCISE_ROUTE, EXTRA_SESSION_ID)
+        assertThat(extras.getParcelable(EXTRA_EXERCISE_ROUTE, ExerciseRoute::class.java))
+            .isEqualTo(record.route)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+        assertPermissionRevoked(ROUTE_READER_WRITER_APP, READ_EXERCISE_ROUTES)
+    }
+
+    @Test
+    fun requestRoute_showsDialog_clickAllowAll_returnsRoute_grantsPermission() {
+        val record = getExerciseSessionWithRoute()
+        val recordId = insertRecordAndGetId(record)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+
+        val result =
+            ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent) {
+                waitDisplayed(By.text("Allow this route"))
+                scrollDownTo(By.text("Don't allow"))
+                clickOnText("Allow all routes")
+            }
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_OK)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_EXERCISE_ROUTE, EXTRA_SESSION_ID)
+        assertThat(extras.getParcelable(EXTRA_EXERCISE_ROUTE, ExerciseRoute::class.java))
+            .isEqualTo(record.route)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+        assertPermissionGranted(ROUTE_READER_WRITER_APP, READ_EXERCISE_ROUTES)
+    }
+
+    @Test
+    fun requestRoute_showsDialog_clickDeny_returnsNull_permissionRemainsRevoked() {
+        val record = getExerciseSessionWithRoute()
+        val recordId = insertRecordAndGetId(record)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+
+        val result =
+            ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent) {
+                waitDisplayed(By.text("Allow all routes"))
+                waitDisplayed(By.text("Allow this route"))
+                scrollDownTo(By.text("Don't allow"))
+                clickOnText("Don't allow")
+            }
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_CANCELED)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_SESSION_ID)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+        assertPermissionRevoked(ROUTE_READER_WRITER_APP, READ_EXERCISE_ROUTES)
+    }
+
+    @Test
+    fun requestRoute_ownSession_doesNotShowDialog_returnsRoute() {
+        val record = getExerciseSessionWithRoute()
+        val recordId: String = ROUTE_READER_WRITER_APP.insertRecords(record).get(0)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+
+        val result = ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent)
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_OK)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_EXERCISE_ROUTE, EXTRA_SESSION_ID)
+        assertThat(extras.getParcelable(EXTRA_EXERCISE_ROUTE, ExerciseRoute::class.java))
+            .isEqualTo(record.route)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+        assertPermissionRevoked(ROUTE_READER_WRITER_APP, READ_EXERCISE_ROUTES)
+    }
+
+    @Test
+    fun requestRoute_withReadRoutesGranted_doesNotShowDialog_returnsRoute() {
+        val record = getExerciseSessionWithRoute()
+        val recordId = insertRecordAndGetId(record)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+        grantPermission(ROUTE_READER_WRITER_APP.getPackageName(), READ_EXERCISE_ROUTES)
+
+        val result = ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent)
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_OK)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_EXERCISE_ROUTE, EXTRA_SESSION_ID)
+        assertThat(extras.getParcelable(EXTRA_EXERCISE_ROUTE, ExerciseRoute::class.java))
+            .isEqualTo(record.route)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+        assertPermissionGranted(ROUTE_READER_WRITER_APP, READ_EXERCISE_ROUTES)
+    }
+
+    @Test
+    fun requestRoute_sessionWithoutRoute_returnsNull() {
+        val record = getExerciseSessionWithoutRoute()
+        val recordId = insertRecordAndGetId(record)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+
+        val result = ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent)
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_CANCELED)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_SESSION_ID)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+        assertPermissionRevoked(ROUTE_READER_WRITER_APP, READ_EXERCISE_ROUTES)
+    }
+
+    @Test
+    fun requestRoute_nonExistingSession_returnsNull() {
+        val requestIntent = Intent(ACTION_REQUEST_EXERCISE_ROUTE)
+        requestIntent.putExtra(EXTRA_SESSION_ID, "nonExistingId")
+
+        val result = ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent)
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_CANCELED)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_SESSION_ID)
+        assertPermissionRevoked(ROUTE_READER_WRITER_APP, READ_EXERCISE_ROUTES)
+    }
+
+    @Test
+    fun requestRoute_sessionIdNotSet_returnsNull() {
+        val requestIntent = Intent(ACTION_REQUEST_EXERCISE_ROUTE)
+
+        val result = ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent)
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_CANCELED)
+        assertThat(result.resultData.extras).isNull()
+        assertPermissionRevoked(ROUTE_READER_WRITER_APP, READ_EXERCISE_ROUTES)
+    }
+
+    @Test
+    fun requestRoute_withReadWriteRoutePermissionsRevoked_showsDialog_returnsRoute() {
+        val record = getExerciseSessionWithRoute()
+        val recordId = insertRecordAndGetId(record)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+
+        val result =
+            runWithRevokedPermission(
+                ROUTE_READER_WRITER_APP.getPackageName(), HealthPermissions.WRITE_EXERCISE_ROUTE) {
+                    ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent) {
+                        waitDisplayed(By.text("Allow this route"))
+                        scrollDownTo(By.text("Don't allow"))
+                        clickOnText("Allow all routes")
+                    }
+                }
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_OK)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_EXERCISE_ROUTE, EXTRA_SESSION_ID)
+        assertThat(extras.getParcelable(EXTRA_EXERCISE_ROUTE, ExerciseRoute::class.java))
+            .isEqualTo(record.route)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+        assertPermissionGranted(ROUTE_READER_WRITER_APP, READ_EXERCISE_ROUTES)
+    }
+
+    @Test
+    fun requestRoute_readExercisePermissionRevoked_throwsSecurityException() {
+        val record = getExerciseSessionWithRoute()
+        val recordId = insertRecordAndGetId(record)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+        grantPermission(ROUTE_READER_WRITER_APP.getPackageName(), READ_EXERCISE_ROUTES)
+
+        assertThrows(SecurityException::class.java) {
+            runWithRevokedPermission(
+                ROUTE_READER_WRITER_APP.getPackageName(), HealthPermissions.READ_EXERCISE) {
+                    ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent)
+                }
+        }
+    }
+
+    @Test
+    fun requestRoute_withoutReadRoutesPermissionDeclared_doesNotShowDialog_returnsNull() {
+        assertThat(getDeclaredHealthPermissions(context.packageName))
+            .doesNotContain(READ_EXERCISE_ROUTES)
+        val record = getExerciseSessionWithRoute()
+        val recordId = insertRecordAndGetId(record)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+
+        val result = ProxyActivity.launchActivityForResult(requestIntent) {}
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_CANCELED)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_SESSION_ID)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+    }
+
+    @Test
+    fun requestRoute_readRoutesPermissionDeniedUserFixed_doesNotShowDialog_returnsNull() {
+        val record = getExerciseSessionWithRoute()
+        val recordId = insertRecordAndGetId(record)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+
+        val result =
+            runWithUserFixedPermission(
+                ROUTE_READER_WRITER_APP.getPackageName(), READ_EXERCISE_ROUTES) {
+                    ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent)
+                }
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_CANCELED)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_SESSION_ID)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+    }
+
+    @Test
+    fun requestRoute_allowAllFeatureOff_allowAllNotDisplayed() {
+        val record = getExerciseSessionWithRoute()
+        val recordId = insertRecordAndGetId(record)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+
+        val result =
+            runWithDeviceConfigForController(READ_ROUTES_ALL_FEATURE_FLAG, "false") {
+                ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent) {
+                    waitNotDisplayed(By.text("Allow all routes"))
+                    waitDisplayed(By.text("Don't allow"))
+                    clickOnText("Allow this route")
+                }
+            }
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_OK)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_EXERCISE_ROUTE, EXTRA_SESSION_ID)
+        assertThat(extras.getParcelable(EXTRA_EXERCISE_ROUTE, ExerciseRoute::class.java))
+            .isEqualTo(record.route)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+    }
+
+    @Test
+    fun requestRoute_enforcesAccessTimeLimits() {
+        val record =
+            getExerciseSessionWithRoute(
+                TestUtils.yesterdayAt("11:00")
+                    .minus(Duration.ofDays(30))
+                    .minus(Duration.ofHours(1)))
+        val recordId = insertRecordAndGetId(record)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+
+        val result = ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent)
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_CANCELED)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_SESSION_ID)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+    }
+
+    @Test
+    fun requestRoute_ownRoute_ignoresAccessTimeLimits() {
+        val record =
+            getExerciseSessionWithRoute(TestUtils.yesterdayAt("11:00").minus(Duration.ofDays(60)))
+        val recordId: String = ROUTE_READER_WRITER_APP.insertRecords(record).get(0)
+        val requestIntent =
+            Intent(ACTION_REQUEST_EXERCISE_ROUTE).putExtra(EXTRA_SESSION_ID, recordId)
+
+        val result = ROUTE_READER_WRITER_APP.startActivityForResult(requestIntent)
+
+        assertThat(result.resultCode).isEqualTo(Activity.RESULT_OK)
+        val extras = result.resultData.extras!!
+        assertThat(extras.keySet()).containsExactly(EXTRA_EXERCISE_ROUTE, EXTRA_SESSION_ID)
+        assertThat(extras.getParcelable(EXTRA_EXERCISE_ROUTE, ExerciseRoute::class.java))
+            .isEqualTo(record.route)
+        assertThat(extras.getString(EXTRA_SESSION_ID)).isEqualTo(recordId)
+    }
+
+    private fun assertPermissionGranted(testAppProxy: TestAppProxy, permission: String) {
+        assertThat(context.packageManager.checkPermission(permission, testAppProxy.packageName))
+            .isEqualTo(PackageManager.PERMISSION_GRANTED)
+    }
+
+    private fun assertPermissionRevoked(testAppProxy: TestAppProxy, permission: String) {
+        assertThat(context.packageManager.checkPermission(permission, testAppProxy.packageName))
+            .isEqualTo(PackageManager.PERMISSION_DENIED)
+    }
+
+    private fun getExerciseSessionWithRoute() =
+        getExerciseSessionWithRoute(TestUtils.yesterdayAt("11:00"))
+
+    private fun getExerciseSessionWithRoute(startTime: Instant) =
+        ExerciseSessionRecord.Builder(
+                getEmptyMetadata(),
+                startTime,
+                startTime.plus(Duration.ofMinutes(30)),
+                ExerciseSessionType.EXERCISE_SESSION_TYPE_RUNNING)
+            .setRoute(
+                ExerciseRoute(
+                    listOf(
+                        ExerciseRoute.Location.Builder(startTime.plusSeconds(5), 13.0, -22.0)
+                            .build())))
+            .build()
+
+    private fun getExerciseSessionWithoutRoute(): ExerciseSessionRecord {
+        val startTime = TestUtils.yesterdayAt("11:00")
+        return ExerciseSessionRecord.Builder(
+                getEmptyMetadata(),
+                startTime,
+                startTime.plus(Duration.ofMinutes(30)),
+                ExerciseSessionType.EXERCISE_SESSION_TYPE_RUNNING)
+            .build()
+    }
+}
diff --git a/tests/cts/src/android/healthconnect/cts/ui/HomeFragmentTest.kt b/tests/cts/src/android/healthconnect/cts/ui/HomeFragmentTest.kt
index c5828ed..f259bee 100644
--- a/tests/cts/src/android/healthconnect/cts/ui/HomeFragmentTest.kt
+++ b/tests/cts/src/android/healthconnect/cts/ui/HomeFragmentTest.kt
@@ -16,17 +16,17 @@
 package android.healthconnect.cts.ui
 
 import android.health.connect.TimeInstantRangeFilter
-import android.health.connect.datatypes.BasalMetabolicRateRecord
-import android.health.connect.datatypes.HeartRateRecord
 import android.health.connect.datatypes.StepsRecord
 import android.healthconnect.cts.lib.ActivityLauncher.launchMainActivity
-import android.healthconnect.cts.lib.MultiAppTestUtils.insertRecordAs
+import android.healthconnect.cts.lib.TestAppProxy
 import android.healthconnect.cts.lib.UiTestUtils.clickOnText
 import android.healthconnect.cts.lib.UiTestUtils.waitDisplayed
+import android.healthconnect.cts.utils.DataFactory.getEmptyMetadata
+import android.healthconnect.cts.utils.TestUtils
 import android.healthconnect.cts.utils.TestUtils.verifyDeleteRecords
 import androidx.test.uiautomator.By
-import com.android.cts.install.lib.TestApp
 import java.time.Instant
+import java.time.temporal.ChronoUnit
 import org.junit.AfterClass
 import org.junit.BeforeClass
 import org.junit.Test
@@ -36,45 +36,32 @@
 
     companion object {
 
-        private const val TAG = "HomeFragmentTest"
-
-        private const val VERSION_CODE: Long = 1
-
-        private val APP_A_WITH_READ_WRITE_PERMS: TestApp =
-            TestApp(
-                "TestAppA",
-                "android.healthconnect.cts.testapp.readWritePerms.A",
-                VERSION_CODE,
-                false,
-                "CtsHealthConnectTestAppA.apk")
+        private val APP_A_WITH_READ_WRITE_PERMS: TestAppProxy =
+            TestAppProxy.forPackageName("android.healthconnect.cts.testapp.readWritePerms.A")
 
         @JvmStatic
         @BeforeClass
         fun setup() {
-            insertRecordAs(APP_A_WITH_READ_WRITE_PERMS)
+            if (!TestUtils.isHardwareSupported()) {
+                return
+            }
+            val now = Instant.now().truncatedTo(ChronoUnit.MILLIS)
+            APP_A_WITH_READ_WRITE_PERMS.insertRecords(
+                StepsRecord.Builder(getEmptyMetadata(), now.minusSeconds(30), now, 43).build())
         }
 
         @JvmStatic
         @AfterClass
         fun teardown() {
+            if (!TestUtils.isHardwareSupported()) {
+                return
+            }
             verifyDeleteRecords(
                 StepsRecord::class.java,
                 TimeInstantRangeFilter.Builder()
                     .setStartTime(Instant.EPOCH)
                     .setEndTime(Instant.now())
                     .build())
-            verifyDeleteRecords(
-                HeartRateRecord::class.java,
-                TimeInstantRangeFilter.Builder()
-                    .setStartTime(Instant.EPOCH)
-                    .setEndTime(Instant.now())
-                    .build())
-            verifyDeleteRecords(
-                BasalMetabolicRateRecord::class.java,
-                TimeInstantRangeFilter.Builder()
-                    .setStartTime(Instant.EPOCH)
-                    .setEndTime(Instant.now())
-                    .build())
         }
     }
 
diff --git a/tests/cts/src/android/healthconnect/cts/ui/PermissionTypesFragmentTest.kt b/tests/cts/src/android/healthconnect/cts/ui/PermissionTypesFragmentTest.kt
index 9ff9024..dcedf21 100644
--- a/tests/cts/src/android/healthconnect/cts/ui/PermissionTypesFragmentTest.kt
+++ b/tests/cts/src/android/healthconnect/cts/ui/PermissionTypesFragmentTest.kt
@@ -19,14 +19,16 @@
 import android.health.connect.datatypes.BasalMetabolicRateRecord
 import android.health.connect.datatypes.HeartRateRecord
 import android.health.connect.datatypes.StepsRecord
-import android.healthconnect.cts.utils.TestUtils.verifyDeleteRecords
 import android.healthconnect.cts.lib.ActivityLauncher.launchDataActivity
-import android.healthconnect.cts.lib.MultiAppTestUtils.insertRecordAs
+import android.healthconnect.cts.lib.TestAppProxy
 import android.healthconnect.cts.lib.UiTestUtils.clickOnText
 import android.healthconnect.cts.lib.UiTestUtils.waitDisplayed
+import android.healthconnect.cts.utils.DataFactory.getEmptyMetadata
+import android.healthconnect.cts.utils.TestUtils
+import android.healthconnect.cts.utils.TestUtils.verifyDeleteRecords
 import androidx.test.uiautomator.By
-import com.android.cts.install.lib.TestApp
 import java.time.Instant
+import java.time.temporal.ChronoUnit
 import org.junit.AfterClass
 import org.junit.BeforeClass
 import org.junit.Test
@@ -35,36 +37,30 @@
 class PermissionTypesFragmentTest : HealthConnectBaseTest() {
 
     companion object {
-        private const val TAG = "PermissionTypesFragmentTest"
-
-        private const val VERSION_CODE: Long = 1
-
-        private val APP_A_WITH_READ_WRITE_PERMS: TestApp =
-            TestApp(
-                "TestAppA",
-                "android.healthconnect.cts.testapp.readWritePerms.A",
-                VERSION_CODE,
-                false,
-                "CtsHealthConnectTestAppA.apk")
-
-        private val APP_B_WITH_READ_WRITE_PERMS: TestApp =
-            TestApp(
-                "TestAppB",
-                "android.healthconnect.cts.testapp.readWritePerms.B",
-                VERSION_CODE,
-                false,
-                "CtsHealthConnectTestAppB.apk")
+        private val APP_A_WITH_READ_WRITE_PERMS: TestAppProxy =
+            TestAppProxy.forPackageName("android.healthconnect.cts.testapp.readWritePerms.A")
+        private val APP_B_WITH_READ_WRITE_PERMS: TestAppProxy =
+            TestAppProxy.forPackageName("android.healthconnect.cts.testapp.readWritePerms.B")
 
         @JvmStatic
         @BeforeClass
         fun setup() {
-            insertRecordAs(APP_A_WITH_READ_WRITE_PERMS)
-            insertRecordAs(APP_B_WITH_READ_WRITE_PERMS)
+            if (!TestUtils.isHardwareSupported()) {
+                return
+            }
+            val now = Instant.now().truncatedTo(ChronoUnit.MILLIS)
+            val record =
+                StepsRecord.Builder(getEmptyMetadata(), now.minusSeconds(30), now, 43).build()
+            APP_A_WITH_READ_WRITE_PERMS.insertRecords(record)
+            APP_B_WITH_READ_WRITE_PERMS.insertRecords(record)
         }
 
         @JvmStatic
         @AfterClass
         fun teardown() {
+            if (!TestUtils.isHardwareSupported()) {
+                return
+            }
             verifyDeleteRecords(
                 StepsRecord::class.java,
                 TimeInstantRangeFilter.Builder()
diff --git a/tests/cts/src/android/healthconnect/cts/ui/permissions/ManageAppHealthPermissionUITest.kt b/tests/cts/src/android/healthconnect/cts/ui/permissions/ManageAppHealthPermissionUITest.kt
index ef87c34..22a61ca 100644
--- a/tests/cts/src/android/healthconnect/cts/ui/permissions/ManageAppHealthPermissionUITest.kt
+++ b/tests/cts/src/android/healthconnect/cts/ui/permissions/ManageAppHealthPermissionUITest.kt
@@ -17,12 +17,10 @@
 package android.healthconnect.cts.ui.permissions
 
 import android.content.pm.PackageManager
-import android.health.connect.HealthPermissions
 import android.health.connect.HealthPermissions.READ_HEIGHT
 import android.health.connect.HealthPermissions.WRITE_BODY_FAT
 import android.health.connect.HealthPermissions.WRITE_HEIGHT
 import android.healthconnect.cts.lib.ActivityLauncher.launchMainActivity
-import android.healthconnect.cts.lib.UiTestUtils
 import android.healthconnect.cts.lib.UiTestUtils.TEST_APP_PACKAGE_NAME
 import android.healthconnect.cts.lib.UiTestUtils.clickOnContentDescription
 import android.healthconnect.cts.lib.UiTestUtils.clickOnText
@@ -33,9 +31,7 @@
 import android.healthconnect.cts.ui.HealthConnectBaseTest
 import androidx.test.uiautomator.By
 import com.google.common.truth.Truth.assertThat
-import java.lang.Exception
 import org.junit.After
-import org.junit.Ignore
 import org.junit.Test
 
 class ManageAppHealthPermissionUITest : HealthConnectBaseTest() {
@@ -104,20 +100,20 @@
             clickOnText("Allow all")
             waitDisplayed(By.text("Remove all permissions?"))
             waitDisplayed(
-                    By.text("Also delete Health Connect cts test app data from Health Connect"))
+                By.text("Also delete Health Connect cts test app data from Health Connect"))
         }
     }
 
     @Throws(Exception::class)
     private fun assertPermNotGrantedForApp(packageName: String, permName: String) {
         assertThat(context.packageManager.checkPermission(permName, packageName))
-                .isEqualTo(PackageManager.PERMISSION_DENIED)
+            .isEqualTo(PackageManager.PERMISSION_DENIED)
     }
 
     @Throws(Exception::class)
     private fun assertPermGrantedForApp(packageName: String, permName: String) {
         assertThat(context.packageManager.checkPermission(permName, packageName))
-                .isEqualTo(PackageManager.PERMISSION_GRANTED)
+            .isEqualTo(PackageManager.PERMISSION_GRANTED)
     }
 
     private fun navigateToManageAppPermissions() {
@@ -129,11 +125,9 @@
 
     @After
     fun tearDown() {
-        revokePermissionViaPackageManager(context, TEST_APP_PACKAGE_NAME, READ_HEIGHT)
-        revokePermissionViaPackageManager(
-                context, TEST_APP_PACKAGE_NAME, WRITE_HEIGHT)
-        revokePermissionViaPackageManager(
-                context, TEST_APP_PACKAGE_NAME, WRITE_BODY_FAT)
+        grantPermissionViaPackageManager(context, TEST_APP_PACKAGE_NAME, READ_HEIGHT)
+        grantPermissionViaPackageManager(context, TEST_APP_PACKAGE_NAME, WRITE_HEIGHT)
+        grantPermissionViaPackageManager(context, TEST_APP_PACKAGE_NAME, WRITE_BODY_FAT)
         navigateBackToHomeScreen()
     }
 }
diff --git a/tests/cts/src/android/healthconnect/cts/ui/permissions/ManageHealthPermissionsUITest.kt b/tests/cts/src/android/healthconnect/cts/ui/permissions/ManageHealthPermissionsUITest.kt
index 101f132..9b0dfc1 100644
--- a/tests/cts/src/android/healthconnect/cts/ui/permissions/ManageHealthPermissionsUITest.kt
+++ b/tests/cts/src/android/healthconnect/cts/ui/permissions/ManageHealthPermissionsUITest.kt
@@ -23,7 +23,6 @@
 import android.healthconnect.cts.lib.UiTestUtils.clickOnContentDescription
 import android.healthconnect.cts.lib.UiTestUtils.clickOnText
 import android.healthconnect.cts.lib.UiTestUtils.grantPermissionViaPackageManager
-import android.healthconnect.cts.lib.UiTestUtils.revokePermissionViaPackageManager
 import android.healthconnect.cts.lib.UiTestUtils.waitDisplayed
 import android.healthconnect.cts.ui.HealthConnectBaseTest
 import androidx.test.uiautomator.By
@@ -38,7 +37,6 @@
     fun showsListOfHealthConnectApps() {
         context.launchMainActivity {
             navigateToManagePermissions()
-
             waitDisplayed(By.text("Health Connect cts test app"))
         }
     }
@@ -83,11 +81,11 @@
 
     @After
     fun tearDown() {
-        revokePermissionViaPackageManager(
+        grantPermissionViaPackageManager(
             context, TEST_APP_PACKAGE_NAME, HealthPermissions.READ_HEIGHT)
-        revokePermissionViaPackageManager(
+        grantPermissionViaPackageManager(
             context, TEST_APP_PACKAGE_NAME, HealthPermissions.WRITE_HEIGHT)
-        revokePermissionViaPackageManager(
+        grantPermissionViaPackageManager(
             context, TEST_APP_PACKAGE_NAME, HealthPermissions.WRITE_BODY_FAT)
     }
 
diff --git a/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/AssumptionCheckerRule.java b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/AssumptionCheckerRule.java
new file mode 100644
index 0000000..b13b23b
--- /dev/null
+++ b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/AssumptionCheckerRule.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.cts.utils;
+
+import static org.junit.Assume.assumeTrue;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.util.function.BooleanSupplier;
+
+/**
+ * Rule which checks an assumption, and skips the test if it evaluates false. Primarily useful for
+ * short-circuiting rule evaluations.
+ */
+public class AssumptionCheckerRule implements TestRule {
+
+    private final String mAssumptionDescription;
+    private final BooleanSupplier mShouldRunTestSupplier;
+
+    /**
+     * Initialize the rule with a supplier to assume on and a description.
+     *
+     * @param shouldRunTestSupplier - Evaluated prior to each test statement, and if false, test is
+     *     skipped.
+     * @param description - Message for failed assumption if test is skipped.
+     */
+    public AssumptionCheckerRule(BooleanSupplier shouldRunTestSupplier, String description) {
+        mShouldRunTestSupplier = shouldRunTestSupplier;
+        mAssumptionDescription = description;
+    }
+
+    @Override
+    public Statement apply(Statement base, Description description) {
+        return new Statement() {
+            @Override
+            public void evaluate() throws Throwable {
+                assumeTrue(mAssumptionDescription, mShouldRunTestSupplier.getAsBoolean());
+                base.evaluate();
+            }
+        };
+    }
+
+    @Override
+    public String toString() {
+        return "AssumptionCheckerRule["
+                + mAssumptionDescription
+                + ", "
+                + mShouldRunTestSupplier
+                + "]";
+    }
+}
diff --git a/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/DataFactory.java b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/DataFactory.java
new file mode 100644
index 0000000..9e0c486
--- /dev/null
+++ b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/DataFactory.java
@@ -0,0 +1,371 @@
+/*
+ * Copyright (C) 2024 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 android.healthconnect.cts.utils;
+
+import static android.health.connect.datatypes.Metadata.RECORDING_METHOD_ACTIVELY_RECORDED;
+import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_BASAL_METABOLIC_RATE;
+import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_HEART_RATE;
+import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_STEPS;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.health.connect.datatypes.BasalMetabolicRateRecord;
+import android.health.connect.datatypes.DataOrigin;
+import android.health.connect.datatypes.Device;
+import android.health.connect.datatypes.DistanceRecord;
+import android.health.connect.datatypes.ExerciseLap;
+import android.health.connect.datatypes.ExerciseRoute;
+import android.health.connect.datatypes.ExerciseSegment;
+import android.health.connect.datatypes.ExerciseSegmentType;
+import android.health.connect.datatypes.ExerciseSessionRecord;
+import android.health.connect.datatypes.ExerciseSessionType;
+import android.health.connect.datatypes.HeartRateRecord;
+import android.health.connect.datatypes.Metadata;
+import android.health.connect.datatypes.Record;
+import android.health.connect.datatypes.SleepSessionRecord;
+import android.health.connect.datatypes.StepsRecord;
+import android.health.connect.datatypes.TotalCaloriesBurnedRecord;
+import android.health.connect.datatypes.units.Energy;
+import android.health.connect.datatypes.units.Length;
+import android.health.connect.datatypes.units.Power;
+import android.healthconnect.cts.utils.TestUtils.RecordAndIdentifier;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoUnit;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+
+public final class DataFactory {
+    public static final Instant SESSION_START_TIME = Instant.now().minus(10, ChronoUnit.DAYS);
+    public static final Instant SESSION_END_TIME =
+            Instant.now().minus(10, ChronoUnit.DAYS).plus(1, ChronoUnit.HOURS);
+
+    public static Device buildDevice() {
+        return new Device.Builder()
+                .setManufacturer("google")
+                .setModel("Pixel4a")
+                .setType(2)
+                .build();
+    }
+
+    public static Metadata generateMetadata() {
+        return generateMetadata(UUID.randomUUID().toString());
+    }
+
+    public static Metadata generateMetadata(String id) {
+        Context context = ApplicationProvider.getApplicationContext();
+        return new Metadata.Builder()
+                .setDevice(buildDevice())
+                .setId(id)
+                .setClientRecordId("clientRecordId" + Math.random())
+                .setDataOrigin(
+                        new DataOrigin.Builder().setPackageName(context.getPackageName()).build())
+                .setRecordingMethod(Metadata.RECORDING_METHOD_UNKNOWN)
+                .build();
+    }
+
+    public static Metadata getEmptyMetadata() {
+        return new Metadata.Builder().build();
+    }
+
+    /** Creates a {@link Metadata} with the given record id. */
+    public static Metadata getMetadataForId(String id) {
+        return new Metadata.Builder().setId(id).build();
+    }
+
+    /** Creates a {@link Metadata} with the given record id and data origin. */
+    public static Metadata getMetadataForId(String id, DataOrigin dataOrigin) {
+        return new Metadata.Builder().setId(id).setDataOrigin(dataOrigin).build();
+    }
+
+    /** Creates a {@link Metadata} with the given client record id. */
+    public static Metadata getMetadataForClientId(String clientId) {
+        return new Metadata.Builder().setClientRecordId(clientId).build();
+    }
+
+    /** Creates a {@link Metadata} with the given client record id. */
+    public static Metadata getMetadataForClientId(String clientId, DataOrigin dataOrigin) {
+        return new Metadata.Builder().setClientRecordId(clientId).setDataOrigin(dataOrigin).build();
+    }
+
+    /** Creates a {@link Metadata} with the given client record id. */
+    public static Metadata getMetadataForClientIdAndVersion(String clientId, long clientVersion) {
+        return new Metadata.Builder()
+                .setClientRecordId(clientId)
+                .setClientRecordVersion(clientVersion)
+                .build();
+    }
+
+    /** Creates a {@link Metadata} with the given data origin. */
+    public static Metadata getMetadata(DataOrigin dataOrigin) {
+        return new Metadata.Builder().setDataOrigin(dataOrigin).build();
+    }
+
+    /** Creates a {@link DataOrigin} with the given package name. */
+    public static DataOrigin getDataOrigin(String packageName) {
+        return new DataOrigin.Builder().setPackageName(packageName).build();
+    }
+
+    /** Creates a list of {@link DataOrigin} from a list of package names. */
+    public static List<DataOrigin> getDataOrigins(String... packageNames) {
+        return Arrays.stream(packageNames).map(DataFactory::getDataOrigin).toList();
+    }
+
+    public static SleepSessionRecord buildSleepSession() {
+        return new SleepSessionRecord.Builder(
+                        generateMetadata(), SESSION_START_TIME, SESSION_END_TIME)
+                .setNotes("warm")
+                .setTitle("Afternoon nap")
+                .setStages(
+                        List.of(
+                                new SleepSessionRecord.Stage(
+                                        SESSION_START_TIME,
+                                        SESSION_START_TIME.plusSeconds(300),
+                                        SleepSessionRecord.StageType.STAGE_TYPE_SLEEPING_LIGHT),
+                                new SleepSessionRecord.Stage(
+                                        SESSION_START_TIME.plusSeconds(300),
+                                        SESSION_START_TIME.plusSeconds(600),
+                                        SleepSessionRecord.StageType.STAGE_TYPE_SLEEPING_REM),
+                                new SleepSessionRecord.Stage(
+                                        SESSION_START_TIME.plusSeconds(900),
+                                        SESSION_START_TIME.plusSeconds(1200),
+                                        SleepSessionRecord.StageType.STAGE_TYPE_SLEEPING_DEEP)))
+                .build();
+    }
+
+    public static ExerciseSessionRecord buildExerciseSession() {
+        return new ExerciseSessionRecord.Builder(
+                        generateMetadata(),
+                        SESSION_START_TIME,
+                        SESSION_END_TIME,
+                        ExerciseSessionType.EXERCISE_SESSION_TYPE_OTHER_WORKOUT)
+                .setRoute(buildExerciseRoute())
+                .setLaps(
+                        List.of(
+                                new ExerciseLap.Builder(
+                                                SESSION_START_TIME,
+                                                SESSION_START_TIME.plusSeconds(20))
+                                        .setLength(Length.fromMeters(10))
+                                        .build(),
+                                new ExerciseLap.Builder(
+                                                SESSION_END_TIME.minusSeconds(20), SESSION_END_TIME)
+                                        .build()))
+                .setSegments(
+                        List.of(
+                                new ExerciseSegment.Builder(
+                                                SESSION_START_TIME.plusSeconds(1),
+                                                SESSION_START_TIME.plusSeconds(10),
+                                                ExerciseSegmentType
+                                                        .EXERCISE_SEGMENT_TYPE_BENCH_PRESS)
+                                        .build(),
+                                new ExerciseSegment.Builder(
+                                                SESSION_START_TIME.plusSeconds(21),
+                                                SESSION_START_TIME.plusSeconds(124),
+                                                ExerciseSegmentType.EXERCISE_SEGMENT_TYPE_BURPEE)
+                                        .setRepetitionsCount(15)
+                                        .build()))
+                .setEndZoneOffset(ZoneOffset.MAX)
+                .setStartZoneOffset(ZoneOffset.MIN)
+                .setNotes("rain")
+                .setTitle("Morning training")
+                .build();
+    }
+
+    public static ExerciseRoute buildExerciseRoute() {
+        return new ExerciseRoute(
+                List.of(
+                        buildLocationTimePoint(SESSION_START_TIME),
+                        buildLocationTimePoint(SESSION_START_TIME),
+                        buildLocationTimePoint(SESSION_START_TIME)));
+    }
+
+    public static ExerciseRoute.Location buildLocationTimePoint(Instant startTime) {
+        return new ExerciseRoute.Location.Builder(
+                        Instant.ofEpochMilli(
+                                (long) (startTime.toEpochMilli() + 10 + Math.random() * 50)),
+                        Math.random() * 50,
+                        Math.random() * 50)
+                .build();
+    }
+
+    public static HeartRateRecord getHeartRateRecord() {
+        return getHeartRateRecord(72);
+    }
+
+    public static HeartRateRecord getHeartRateRecord(int heartRate, String clientId) {
+        return getHeartRateRecord(heartRate, Instant.now().plusMillis(100), clientId);
+    }
+
+    public static HeartRateRecord getHeartRateRecord(int heartRate) {
+        return getHeartRateRecord(heartRate, Instant.now().plusMillis(100));
+    }
+
+    public static HeartRateRecord getHeartRateRecord(int heartRate, Instant instant) {
+        return getHeartRateRecord(heartRate, instant, "HR" + Math.random());
+    }
+
+    public static HeartRateRecord getHeartRateRecord(
+            int heartRate, Instant instant, String clientId) {
+        String packageName = ApplicationProvider.getApplicationContext().getPackageName();
+        HeartRateRecord.HeartRateSample heartRateSample =
+                new HeartRateRecord.HeartRateSample(heartRate, instant);
+        ArrayList<HeartRateRecord.HeartRateSample> heartRateSamples = new ArrayList<>();
+        heartRateSamples.add(heartRateSample);
+        heartRateSamples.add(heartRateSample);
+        Device device = buildDevice();
+        DataOrigin dataOrigin = new DataOrigin.Builder().setPackageName(packageName).build();
+
+        return new HeartRateRecord.Builder(
+                        new Metadata.Builder()
+                                .setDevice(device)
+                                .setDataOrigin(dataOrigin)
+                                .setClientRecordId(clientId)
+                                .build(),
+                        instant.minusMillis(100),
+                        instant.plusMillis(100),
+                        heartRateSamples)
+                .build();
+    }
+
+    public static StepsRecord getStepsRecord() {
+        return getStepsRecord(10);
+    }
+
+    public static StepsRecord getStepsRecord(int steps) {
+        return new StepsRecord.Builder(
+                        generateMetadata(), Instant.now(), Instant.now().plusMillis(1000), steps)
+                .build();
+    }
+
+    public static StepsRecord getStepsRecord(int steps, String clientId) {
+        return new StepsRecord.Builder(
+                        getMetadataForClientId(clientId),
+                        Instant.now(),
+                        Instant.now().plusMillis(1000),
+                        steps)
+                .build();
+    }
+
+    public static StepsRecord getStepsRecord(
+            int steps, Instant start, Instant end, String clientId) {
+        return new StepsRecord.Builder(getMetadataForClientId(clientId), start, end, steps).build();
+    }
+
+    public static StepsRecord getStepsRecord(String id) {
+        return new StepsRecord.Builder(
+                        generateMetadata(id), Instant.now(), Instant.now().plusMillis(1000), 10)
+                .build();
+    }
+
+    /** Creates and returns a {@link StepsRecord} with default arguments. */
+    public static StepsRecord getCompleteStepsRecord() {
+        return getCompleteStepsRecord(
+                Instant.now(),
+                Instant.now().plusMillis(1000),
+                /* clientRecordId= */ "SR" + Math.random());
+    }
+
+    /** Creates and returns a {@link StepsRecord} with the specified arguments. */
+    public static StepsRecord getCompleteStepsRecord(
+            Instant startTime, Instant endTime, String clientRecordId) {
+        Device device =
+                new Device.Builder().setManufacturer("google").setModel("Pixel").setType(1).build();
+        DataOrigin dataOrigin =
+                new DataOrigin.Builder().setPackageName("android.healthconnect.cts").build();
+
+        Metadata.Builder testMetadataBuilder = new Metadata.Builder();
+        testMetadataBuilder.setDevice(device).setDataOrigin(dataOrigin);
+        testMetadataBuilder.setClientRecordId(clientRecordId);
+        testMetadataBuilder.setRecordingMethod(RECORDING_METHOD_ACTIVELY_RECORDED);
+        Metadata testMetaData = testMetadataBuilder.build();
+        assertThat(testMetaData.getRecordingMethod()).isEqualTo(RECORDING_METHOD_ACTIVELY_RECORDED);
+        return new StepsRecord.Builder(testMetaData, startTime, endTime, 10).build();
+    }
+
+    public static StepsRecord getUpdatedStepsRecord(
+            Record record, String id, String clientRecordId) {
+        Metadata metadata = record.getMetadata();
+        Metadata metadataWithId =
+                new Metadata.Builder()
+                        .setId(id)
+                        .setClientRecordId(clientRecordId)
+                        .setClientRecordVersion(metadata.getClientRecordVersion())
+                        .setDataOrigin(metadata.getDataOrigin())
+                        .setDevice(metadata.getDevice())
+                        .setLastModifiedTime(metadata.getLastModifiedTime())
+                        .build();
+        return new StepsRecord.Builder(
+                        metadataWithId, Instant.now(), Instant.now().plusMillis(2000), 20)
+                .setStartZoneOffset(ZoneOffset.systemDefault().getRules().getOffset(Instant.now()))
+                .setEndZoneOffset(ZoneOffset.systemDefault().getRules().getOffset(Instant.now()))
+                .build();
+    }
+
+    public static DistanceRecord getDistanceRecord() {
+        return getDistanceRecord(10.0, Instant.now(), Instant.now().plusMillis(1000));
+    }
+
+    public static DistanceRecord getDistanceRecord(double distance, Instant start, Instant end) {
+        return new DistanceRecord.Builder(
+                        getEmptyMetadata(), start, end, Length.fromMeters(distance))
+                .build();
+    }
+
+    public static DistanceRecord getDistanceRecord(
+            double distance, Instant start, Instant end, String clientId) {
+        return new DistanceRecord.Builder(
+                        getMetadataForClientId(clientId), start, end, Length.fromMeters(distance))
+                .build();
+    }
+
+    public static TotalCaloriesBurnedRecord getTotalCaloriesBurnedRecord(String clientId) {
+        return new TotalCaloriesBurnedRecord.Builder(
+                        getMetadataForClientId(clientId),
+                        Instant.now(),
+                        Instant.now().plusMillis(1000),
+                        Energy.fromCalories(10.0))
+                .build();
+    }
+
+    public static List<Record> getTestRecords() {
+        return Arrays.asList(
+                getStepsRecord(),
+                getHeartRateRecord(),
+                getBasalMetabolicRateRecord(),
+                buildExerciseSession());
+    }
+
+    public static List<RecordAndIdentifier> getRecordsAndIdentifiers() {
+        return Arrays.asList(
+                new RecordAndIdentifier(RECORD_TYPE_STEPS, getStepsRecord()),
+                new RecordAndIdentifier(RECORD_TYPE_HEART_RATE, getHeartRateRecord()),
+                new RecordAndIdentifier(
+                        RECORD_TYPE_BASAL_METABOLIC_RATE, getBasalMetabolicRateRecord()));
+    }
+
+    private static BasalMetabolicRateRecord getBasalMetabolicRateRecord() {
+        return new BasalMetabolicRateRecord.Builder(
+                        generateMetadata(), Instant.now(), Power.fromWatts(100.0))
+                .build();
+    }
+}
diff --git a/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/DeviceConfigRule.java b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/DeviceConfigRule.java
new file mode 100644
index 0000000..2aaf505
--- /dev/null
+++ b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/DeviceConfigRule.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2024 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 android.healthconnect.cts.utils;
+
+import static android.healthconnect.cts.utils.TestUtils.getDeviceConfigValue;
+import static android.healthconnect.cts.utils.TestUtils.setDeviceConfigValue;
+
+import org.junit.rules.ExternalResource;
+
+/** Sets a device config value for the duration of the test. */
+public class DeviceConfigRule extends ExternalResource {
+    private final String mKey;
+    private final String mValue;
+    private String mOriginalValue;
+
+    public DeviceConfigRule(String key, String value) {
+        mKey = key;
+        mValue = value;
+    }
+
+    @Override
+    protected void before() throws Throwable {
+        mOriginalValue = getDeviceConfigValue(mKey);
+        setDeviceConfigValue(mKey, mValue);
+    }
+
+    @Override
+    protected void after() {
+        setDeviceConfigValue(mKey, mOriginalValue);
+    }
+}
diff --git a/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/PermissionHelper.java b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/PermissionHelper.java
new file mode 100644
index 0000000..014d913
--- /dev/null
+++ b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/PermissionHelper.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2024 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 android.healthconnect.cts.utils;
+
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.healthconnect.cts.utils.TestUtils.getHealthConnectManager;
+
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.health.connect.HealthConnectManager;
+import android.health.connect.HealthPermissions;
+import android.os.UserHandle;
+
+import androidx.annotation.Nullable;
+
+import com.android.compatibility.common.util.SystemUtil;
+import com.android.compatibility.common.util.ThrowingRunnable;
+import com.android.compatibility.common.util.ThrowingSupplier;
+
+import com.google.common.collect.Sets;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+
+public final class PermissionHelper {
+
+    public static final String MANAGE_HEALTH_DATA = HealthPermissions.MANAGE_HEALTH_DATA_PERMISSION;
+    public static final String READ_EXERCISE_ROUTE_PERMISSION =
+            "android.permission.health.READ_EXERCISE_ROUTE";
+
+    public static final String READ_HEALTH_DATA_IN_BACKGROUND =
+            "android.permission.health.READ_HEALTH_DATA_IN_BACKGROUND";
+    public static final String READ_EXERCISE_ROUTES =
+            "android.permission.health.READ_EXERCISE_ROUTES";
+    private static final String MANAGE_HEALTH_PERMISSIONS =
+            HealthPermissions.MANAGE_HEALTH_PERMISSIONS;
+    private static final String HEALTH_PERMISSION_PREFIX = "android.permission.health.";
+
+    /** Returns permissions declared in the Manifest of the given package. */
+    public static List<String> getDeclaredHealthPermissions(String pkgName) {
+        final PackageInfo pi = getAppPackageInfo(pkgName);
+        final String[] requestedPermissions = pi.requestedPermissions;
+
+        if (requestedPermissions == null) {
+            return List.of();
+        }
+
+        return Arrays.stream(requestedPermissions)
+                .filter(permission -> permission.startsWith(HEALTH_PERMISSION_PREFIX))
+                .toList();
+    }
+
+    public static List<String> getGrantedHealthPermissions(String pkgName) {
+        final PackageInfo pi = getAppPackageInfo(pkgName);
+        final String[] requestedPermissions = pi.requestedPermissions;
+        final int[] requestedPermissionsFlags = pi.requestedPermissionsFlags;
+
+        if (requestedPermissions == null) {
+            return List.of();
+        }
+
+        final List<String> permissions = new ArrayList<>();
+
+        for (int i = 0; i < requestedPermissions.length; i++) {
+            if ((requestedPermissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
+                if (requestedPermissions[i].startsWith(HEALTH_PERMISSION_PREFIX)) {
+                    permissions.add(requestedPermissions[i]);
+                }
+            }
+        }
+
+        return permissions;
+    }
+
+    private static PackageInfo getAppPackageInfo(String pkgName) {
+        final Context targetContext = androidx.test.InstrumentationRegistry.getTargetContext();
+        return runWithShellPermissionIdentity(
+                () ->
+                        targetContext
+                                .getPackageManager()
+                                .getPackageInfo(
+                                        pkgName,
+                                        PackageManager.PackageInfoFlags.of(GET_PERMISSIONS)));
+    }
+
+    public static void grantPermission(String pkgName, String permission) {
+        HealthConnectManager service = getHealthConnectManager();
+        runWithShellPermissionIdentity(
+                () ->
+                        service.getClass()
+                                .getMethod("grantHealthPermission", String.class, String.class)
+                                .invoke(service, pkgName, permission),
+                MANAGE_HEALTH_PERMISSIONS);
+    }
+
+    public static void revokePermission(String pkgName, String permission) {
+        HealthConnectManager service = getHealthConnectManager();
+        runWithShellPermissionIdentity(
+                () ->
+                        service.getClass()
+                                .getMethod(
+                                        "revokeHealthPermission",
+                                        String.class,
+                                        String.class,
+                                        String.class)
+                                .invoke(service, pkgName, permission, null),
+                MANAGE_HEALTH_PERMISSIONS);
+    }
+
+    /**
+     * Utility method to call {@link HealthConnectManager#revokeAllHealthPermissions(String,
+     * String)}.
+     */
+    public static void revokeAllPermissions(String packageName, @Nullable String reason) {
+        HealthConnectManager service = getHealthConnectManager();
+        runWithShellPermissionIdentity(
+                () ->
+                        service.getClass()
+                                .getMethod("revokeAllHealthPermissions", String.class, String.class)
+                                .invoke(service, packageName, reason),
+                MANAGE_HEALTH_PERMISSIONS);
+    }
+
+    /**
+     * Same as {@link #revokeAllPermissions(String, String)} but with a delay to wait for grant time
+     * to be updated.
+     */
+    public static void revokeAllPermissionsWithDelay(String packageName, @Nullable String reason)
+            throws InterruptedException {
+        revokeAllPermissions(packageName, reason);
+        Thread.sleep(500);
+    }
+
+    /** Revokes all granted Health permissions and re-grants them back. */
+    public static void revokeAndThenGrantHealthPermissions(String packageName) {
+        List<String> healthPerms = getGrantedHealthPermissions(packageName);
+
+        revokeHealthPermissions(packageName);
+
+        for (String perm : healthPerms) {
+            grantPermission(packageName, perm);
+        }
+    }
+
+    public static void revokeHealthPermissions(String packageName) {
+        runWithShellPermissionIdentity(() -> revokeHealthPermissionsPrivileged(packageName));
+    }
+
+    private static void revokeHealthPermissionsPrivileged(String packageName)
+            throws PackageManager.NameNotFoundException {
+        final Context targetContext = androidx.test.InstrumentationRegistry.getTargetContext();
+        final PackageManager packageManager = targetContext.getPackageManager();
+        final UserHandle user = targetContext.getUser();
+
+        final PackageInfo packageInfo =
+                packageManager.getPackageInfo(
+                        packageName,
+                        PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS));
+
+        final String[] permissions = packageInfo.requestedPermissions;
+        if (permissions == null) {
+            return;
+        }
+
+        for (String permission : permissions) {
+            if (permission.startsWith(HEALTH_PERMISSION_PREFIX)) {
+                packageManager.revokeRuntimePermission(packageName, permission, user);
+            }
+        }
+    }
+
+    /**
+     * Utility method to call {@link
+     * HealthConnectManager#getHealthDataHistoricalAccessStartDate(String)}.
+     */
+    public static Instant getHealthDataHistoricalAccessStartDate(String packageName) {
+        HealthConnectManager service = getHealthConnectManager();
+        return (Instant)
+                runWithShellPermissionIdentity(
+                        () ->
+                                service.getClass()
+                                        .getMethod(
+                                                "getHealthDataHistoricalAccessStartDate",
+                                                String.class)
+                                        .invoke(service, packageName),
+                        MANAGE_HEALTH_PERMISSIONS);
+    }
+
+    /** Revokes permission for the package for the duration of the runnable. */
+    public static void runWithRevokedPermissions(
+            String packageName, String permission, ThrowingRunnable runnable) throws Exception {
+        runWithRevokedPermissions(
+                (ThrowingSupplier<Void>)
+                        () -> {
+                            runnable.run();
+                            return null;
+                        },
+                packageName,
+                permission);
+    }
+
+    /** Revokes permission for the package for the duration of the supplier. */
+    public static <T> T runWithRevokedPermission(
+            String packageName, String permission, ThrowingSupplier<T> supplier) throws Exception {
+        return runWithRevokedPermissions(supplier, packageName, permission);
+    }
+
+    /** Revokes permission for the package for the duration of the supplier. */
+    public static <T> T runWithRevokedPermissions(
+            ThrowingSupplier<T> supplier, String packageName, String... permissions)
+            throws Exception {
+        Context context = androidx.test.InstrumentationRegistry.getTargetContext();
+        checkArgument(
+                !context.getPackageName().equals(packageName),
+                "Can not be called on self, only on other apps");
+
+        UiAutomation uiAutomation =
+                androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
+                        .getUiAutomation();
+
+        var grantedPermissions =
+                Sets.intersection(
+                        Set.copyOf(getGrantedHealthPermissions(packageName)), Set.of(permissions));
+
+        try {
+            grantedPermissions.forEach(
+                    permission -> uiAutomation.revokeRuntimePermission(packageName, permission));
+            return supplier.get();
+        } finally {
+            grantedPermissions.forEach(
+                    permission -> uiAutomation.grantRuntimePermission(packageName, permission));
+        }
+    }
+
+    /** Flags the permission as USER_FIXED for the duration of the supplier. */
+    public static <T> T runWithUserFixedPermission(
+            String packageName, String permission, ThrowingSupplier<T> supplier) throws Exception {
+        SystemUtil.runShellCommand(
+                String.format("pm set-permission-flags %s %s user-fixed", packageName, permission));
+        try {
+            return supplier.get();
+        } finally {
+            SystemUtil.runShellCommand(
+                    String.format(
+                            "pm clear-permission-flags %s %s user-fixed", packageName, permission));
+        }
+    }
+
+    /**
+     * Sets the device config value for the duration of the supplier.
+     *
+     * <p>Kills the HC controller after each device config update as the most reliable way of making
+     * sure the controller picks up the updated value. Otherwise the callback which the controller
+     * uses to listen to device config changes might arrive late (and usually does).
+     */
+    public static <T> T runWithDeviceConfigForController(
+            String key, String value, ThrowingSupplier<T> supplier) throws Exception {
+        DeviceConfigRule rule = new DeviceConfigRule(key, value);
+        try {
+            rule.before();
+            killHealthConnectController();
+            return supplier.get();
+        } catch (Throwable e) {
+            throw new Exception(e);
+        } finally {
+            rule.after();
+            killHealthConnectController();
+        }
+    }
+
+    /** Kills Health Connect controller. */
+    private static void killHealthConnectController() {
+        SystemUtil.runShellCommandOrThrow(
+                "am force-stop com.google.android.healthconnect.controller");
+    }
+}
diff --git a/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/ProxyActivity.java b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/ProxyActivity.java
new file mode 100644
index 0000000..459a03d
--- /dev/null
+++ b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/ProxyActivity.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2024 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 android.healthconnect.cts.utils;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.compatibility.common.util.UiAutomatorUtils.getUiDevice;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.test.core.app.ActivityScenario;
+
+/**
+ * Activity which starts another activity and forwards the result back to the caller.
+ *
+ * <p>The intent to start a new activity with is encoded as a parcelable extra with key
+ * Intent.EXTRA_INTENT.
+ *
+ * <p>This is useful for two reasons: 1. ActivityScenario often have problems with launching an
+ * activity which belongs to another process. ProxyActivity can be used as a workaround. 2. It can
+ * be used by a test app so that a CTS test can start an activity on behalf of the test app.
+ */
+public class ProxyActivity extends Activity {
+    public static final String PROXY_ACTIVITY_ACTION =
+            "android.healthconnect.cts.ACTION_START_ACTIVITY_FOR_RESULT";
+    public static final String PROXY_ACTIVITY_ERROR =
+            "android.healthconnect.cts.PROXY_ACTIVITY_ERROR";
+    private static final int REQUEST_CODE = 1;
+
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        var requestIntent = getIntent().getParcelableExtra(Intent.EXTRA_INTENT, Intent.class);
+
+        if (requestIntent == null) {
+            finishWithException(new IllegalArgumentException("Missing EXTRA_INTENT extra"));
+            return;
+        }
+
+        try {
+            startActivityForResult(requestIntent, REQUEST_CODE);
+        } catch (Exception e) {
+            finishWithException(e);
+        }
+    }
+
+    @Override
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+        if (requestCode != REQUEST_CODE) {
+            finishWithException(
+                    new IllegalArgumentException("Unexpected request code " + requestCode));
+            return;
+        }
+
+        setResult(resultCode, data);
+        finish();
+    }
+
+    /**
+     * Launch an activity for result with the given intent and executes the runnable once the
+     * activity gets created.
+     *
+     * <p>ActivityScenario.launchActivityForResult doesn't work with activities running in another
+     * process as it times out on waiting for the remote activity to become CREATED. Apparently this
+     * happens because ActivityScenario uses ActivityLifecycleMonitor to track the activity state,
+     * however state changes of the activities which belong to other processes don't trigger the
+     * lifecycle callback and therefore ActivityScenario thinks that the target activity is always
+     * in the PRE_ON_CREATE state even when it's not true. As a workaround this method launches the
+     * proxy activity in the same process which then forwards the intent to the target remote
+     * activity.
+     *
+     * <p>The app calling this method must have {@link ProxyActivity} declared in the manifest.
+     */
+    public static Instrumentation.ActivityResult launchActivityForResult(
+            Intent intent, Runnable runnable) throws Exception {
+
+        Intent containerIntent = new Intent(getInstrumentation().getContext(), ProxyActivity.class);
+        containerIntent.putExtra(Intent.EXTRA_INTENT, intent);
+
+        var scenario = ActivityScenario.launchActivityForResult(containerIntent);
+        scenario.onActivity(
+                activity -> {
+                    getUiDevice().waitForIdle();
+                    runnable.run();
+                });
+
+        Instrumentation.ActivityResult result = scenario.getResult();
+
+        Exception exception =
+                result.getResultData().getParcelableExtra(PROXY_ACTIVITY_ERROR, Exception.class);
+
+        if (exception != null) {
+            throw exception;
+        }
+
+        return result;
+    }
+
+    private void finishWithException(Exception e) {
+        Intent errorIntent = new Intent();
+        errorIntent.putExtra(PROXY_ACTIVITY_ERROR, e);
+        setResult(RESULT_CANCELED, errorIntent);
+        finish();
+    }
+}
diff --git a/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/RevokedHealthPermissionRule.java b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/RevokedHealthPermissionRule.java
new file mode 100644
index 0000000..ba6622e
--- /dev/null
+++ b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/RevokedHealthPermissionRule.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 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 android.healthconnect.cts.utils;
+
+import static android.healthconnect.cts.utils.PermissionHelper.getGrantedHealthPermissions;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import org.junit.rules.ExternalResource;
+
+/** Revokes permission for the given package for the duration of the test. */
+public class RevokedHealthPermissionRule extends ExternalResource {
+
+    private final String mPermission;
+    private final String mPackageName;
+    private boolean mIsPermissionGranted;
+
+    public RevokedHealthPermissionRule(String packageName, String permission) {
+        this.mPermission = permission;
+        this.mPackageName = packageName;
+    }
+
+    @Override
+    protected void before() throws Throwable {
+        var grantedPermissions = getGrantedHealthPermissions(mPackageName);
+
+        mIsPermissionGranted = grantedPermissions.contains(mPermission);
+
+        if (mIsPermissionGranted) {
+            getInstrumentation()
+                    .getUiAutomation()
+                    .revokeRuntimePermission(mPackageName, mPermission);
+        }
+    }
+
+    @Override
+    protected void after() {
+        if (mIsPermissionGranted) {
+            getInstrumentation()
+                    .getUiAutomation()
+                    .grantRuntimePermission(mPackageName, mPermission);
+        }
+    }
+}
diff --git a/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/TestUtils.java b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/TestUtils.java
index 17e776f..e55be39 100644
--- a/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/TestUtils.java
+++ b/tests/cts/utils/HealthConnectTestUtils/src/android/healthconnect/cts/utils/TestUtils.java
@@ -16,7 +16,8 @@
 
 package android.healthconnect.cts.utils;
 
-import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.Manifest.permission.READ_DEVICE_CONFIG;
+import static android.Manifest.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG;
 import static android.health.connect.HealthDataCategory.ACTIVITY;
 import static android.health.connect.HealthDataCategory.BODY_MEASUREMENTS;
 import static android.health.connect.HealthDataCategory.CYCLE_TRACKING;
@@ -27,11 +28,13 @@
 import static android.health.connect.HealthPermissionCategory.EXERCISE;
 import static android.health.connect.HealthPermissionCategory.HEART_RATE;
 import static android.health.connect.HealthPermissionCategory.STEPS;
-import static android.health.connect.datatypes.Metadata.RECORDING_METHOD_ACTIVELY_RECORDED;
-import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_BASAL_METABOLIC_RATE;
-import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_HEART_RATE;
-import static android.health.connect.datatypes.RecordTypeIdentifier.RECORD_TYPE_STEPS;
+import static android.healthconnect.cts.utils.PermissionHelper.MANAGE_HEALTH_DATA;
+import static android.healthconnect.test.app.TestAppReceiver.ACTION_INSERT_STEPS_RECORDS;
+import static android.healthconnect.test.app.TestAppReceiver.EXTRA_END_TIMES;
+import static android.healthconnect.test.app.TestAppReceiver.EXTRA_RECORD_IDS;
+import static android.healthconnect.test.app.TestAppReceiver.EXTRA_RECORD_VALUES;
 import static android.healthconnect.test.app.TestAppReceiver.EXTRA_SENDER_PACKAGE_NAME;
+import static android.healthconnect.test.app.TestAppReceiver.EXTRA_TIMES;
 
 import static com.android.compatibility.common.util.FeatureUtil.AUTOMOTIVE_FEATURE;
 import static com.android.compatibility.common.util.FeatureUtil.hasSystemFeature;
@@ -45,7 +48,6 @@
 import android.app.UiAutomation;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.health.connect.AggregateRecordsGroupedByDurationResponse;
 import android.health.connect.AggregateRecordsGroupedByPeriodResponse;
@@ -58,7 +60,6 @@
 import android.health.connect.HealthConnectException;
 import android.health.connect.HealthConnectManager;
 import android.health.connect.HealthPermissionCategory;
-import android.health.connect.HealthPermissions;
 import android.health.connect.InsertRecordsResponse;
 import android.health.connect.ReadRecordsRequest;
 import android.health.connect.ReadRecordsRequestUsingFilters;
@@ -86,15 +87,9 @@
 import android.health.connect.datatypes.CervicalMucusRecord;
 import android.health.connect.datatypes.CyclingPedalingCadenceRecord;
 import android.health.connect.datatypes.DataOrigin;
-import android.health.connect.datatypes.Device;
 import android.health.connect.datatypes.DistanceRecord;
 import android.health.connect.datatypes.ElevationGainedRecord;
-import android.health.connect.datatypes.ExerciseLap;
-import android.health.connect.datatypes.ExerciseRoute;
-import android.health.connect.datatypes.ExerciseSegment;
-import android.health.connect.datatypes.ExerciseSegmentType;
 import android.health.connect.datatypes.ExerciseSessionRecord;
-import android.health.connect.datatypes.ExerciseSessionType;
 import android.health.connect.datatypes.FloorsClimbedRecord;
 import android.health.connect.datatypes.HeartRateRecord;
 import android.health.connect.datatypes.HeartRateVariabilityRmssdRecord;
@@ -121,68 +116,52 @@
 import android.health.connect.datatypes.Vo2MaxRecord;
 import android.health.connect.datatypes.WeightRecord;
 import android.health.connect.datatypes.WheelchairPushesRecord;
-import android.health.connect.datatypes.units.Length;
-import android.health.connect.datatypes.units.Power;
 import android.health.connect.migration.MigrationEntity;
 import android.health.connect.migration.MigrationException;
 import android.healthconnect.test.app.TestAppReceiver;
 import android.os.Bundle;
 import android.os.OutcomeReceiver;
 import android.os.ParcelFileDescriptor;
-import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.util.Log;
 
 import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
 import androidx.test.core.app.ApplicationProvider;
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import com.android.compatibility.common.util.SystemUtil;
-import com.android.cts.install.lib.TestApp;
-
 import java.io.BufferedReader;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStreamReader;
-import java.io.Serializable;
 import java.time.Duration;
 import java.time.Instant;
 import java.time.LocalDate;
-import java.time.LocalDateTime;
+import java.time.LocalTime;
 import java.time.Period;
-import java.time.ZoneId;
 import java.time.ZoneOffset;
-import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
-import java.util.UUID;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
+import java.util.stream.IntStream;
 
 public final class TestUtils {
-    public static final String MANAGE_HEALTH_PERMISSIONS =
-            HealthPermissions.MANAGE_HEALTH_PERMISSIONS;
-    public static final String READ_EXERCISE_ROUTE_PERMISSION =
-            "android.permission.health.READ_EXERCISE_ROUTE";
-    private static final String HEALTH_PERMISSION_PREFIX = "android.permission.health.";
-    public static final String MANAGE_HEALTH_DATA = HealthPermissions.MANAGE_HEALTH_DATA_PERMISSION;
-    public static final Instant SESSION_START_TIME = Instant.now().minus(10, ChronoUnit.DAYS);
-    public static final Instant SESSION_END_TIME =
-            Instant.now().minus(10, ChronoUnit.DAYS).plus(1, ChronoUnit.HOURS);
     private static final String TAG = "HCTestUtils";
     private static final int TIMEOUT_SECONDS = 5;
 
-    private static final String PKG_TEST_APP = "android.healthconnect.test.app";
+    public static final String PKG_TEST_APP = "android.healthconnect.test.app";
     private static final String TEST_APP_RECEIVER =
             PKG_TEST_APP + "." + TestAppReceiver.class.getSimpleName();
 
@@ -244,37 +223,29 @@
         return returnedRecords;
     }
 
-    public static List<RecordTypeAndRecordIds> insertRecordsAndGetIds(
-            List<Record> records, Context context) throws InterruptedException {
-        List<Record> insertedRecords = insertRecords(records, context);
+    /**
+     * Returns all records from the `records` list in their original order, but distinct by UUID.
+     */
+    public static <T extends Record> List<T> distinctByUuid(List<T> records) {
+        return records.stream().filter(distinctByUuid()).toList();
+    }
 
-        Map<String, List<String>> recordTypeToRecordIdsMap = new HashMap<>();
-        for (Record record : insertedRecords) {
-            recordTypeToRecordIdsMap.putIfAbsent(record.getClass().getName(), new ArrayList<>());
-            recordTypeToRecordIdsMap
-                    .get(record.getClass().getName())
-                    .add(record.getMetadata().getId());
-        }
-
-        List<RecordTypeAndRecordIds> recordTypeAndRecordIdsList = new ArrayList<>();
-        for (String recordType : recordTypeToRecordIdsMap.keySet()) {
-            recordTypeAndRecordIdsList.add(
-                    new RecordTypeAndRecordIds(
-                            recordType, recordTypeToRecordIdsMap.get(recordType)));
-        }
-
-        return recordTypeAndRecordIdsList;
+    private static Predicate<? super Record> distinctByUuid() {
+        Set<String> seen = ConcurrentHashMap.newKeySet();
+        return record -> seen.add(record.getMetadata().getId());
     }
 
     public static void updateRecords(List<Record> records) throws InterruptedException {
         updateRecords(records, ApplicationProvider.getApplicationContext());
     }
 
-    public static void updateRecords(List<Record> records, Context context)
+    /** Synchronously updates records in HC. */
+    public static void updateRecords(List<? extends Record> records, Context context)
             throws InterruptedException {
         HealthConnectReceiver<Void> receiver = new HealthConnectReceiver<>();
         getHealthConnectManager(context)
-                .updateRecords(records, Executors.newSingleThreadExecutor(), receiver);
+                .updateRecords(
+                        unmodifiableList(records), Executors.newSingleThreadExecutor(), receiver);
         receiver.verifyNoExceptionOrThrow();
     }
 
@@ -291,307 +262,6 @@
         return receiver.getResponse();
     }
 
-    public static Device buildDevice() {
-        return new Device.Builder()
-                .setManufacturer("google")
-                .setModel("Pixel4a")
-                .setType(2)
-                .build();
-    }
-
-    private static Metadata buildSessionMetadata(String packageName, double clientId) {
-        Device device =
-                new Device.Builder().setManufacturer("google").setModel("Pixel").setType(1).build();
-        DataOrigin dataOrigin = new DataOrigin.Builder().setPackageName(packageName).build();
-        return new Metadata.Builder()
-                .setDevice(device)
-                .setDataOrigin(dataOrigin)
-                .setClientRecordId(String.valueOf(clientId))
-                .build();
-    }
-
-    public static List<Record> getTestRecords() {
-        return Arrays.asList(
-                getStepsRecord(),
-                getHeartRateRecord(),
-                getBasalMetabolicRateRecord(),
-                buildExerciseSession());
-    }
-
-    public static List<Record> getTestRecords(String packageName) {
-        double clientId = Math.random();
-        return getTestRecords(packageName, clientId);
-    }
-
-    public static List<Record> getTestRecords(String packageName, Double clientId) {
-        return Arrays.asList(
-                getExerciseSessionRecord(packageName, clientId, /* withRoute= */ true),
-                getStepsRecord(packageName, clientId),
-                getHeartRateRecord(packageName, clientId),
-                getBasalMetabolicRateRecord(packageName, clientId));
-    }
-
-    public static List<RecordAndIdentifier> getRecordsAndIdentifiers() {
-        return Arrays.asList(
-                new RecordAndIdentifier(RECORD_TYPE_STEPS, getStepsRecord()),
-                new RecordAndIdentifier(RECORD_TYPE_HEART_RATE, getHeartRateRecord()),
-                new RecordAndIdentifier(
-                        RECORD_TYPE_BASAL_METABOLIC_RATE, getBasalMetabolicRateRecord()));
-    }
-
-    public static ExerciseRoute.Location buildLocationTimePoint(Instant startTime) {
-        return new ExerciseRoute.Location.Builder(
-                        Instant.ofEpochMilli(
-                                (long) (startTime.toEpochMilli() + 10 + Math.random() * 50)),
-                        Math.random() * 50,
-                        Math.random() * 50)
-                .build();
-    }
-
-    public static ExerciseRoute buildExerciseRoute() {
-        return new ExerciseRoute(
-                List.of(
-                        buildLocationTimePoint(SESSION_START_TIME),
-                        buildLocationTimePoint(SESSION_START_TIME),
-                        buildLocationTimePoint(SESSION_START_TIME)));
-    }
-
-    public static StepsRecord getStepsRecord() {
-        double clientId = Math.random();
-        String packageName = ApplicationProvider.getApplicationContext().getPackageName();
-        return getStepsRecord(packageName, clientId);
-    }
-
-    public static StepsRecord getStepsRecord(String packageName, double clientId) {
-        Device device =
-                new Device.Builder().setManufacturer("google").setModel("Pixel").setType(1).build();
-        DataOrigin dataOrigin = new DataOrigin.Builder().setPackageName(packageName).build();
-        return new StepsRecord.Builder(
-                        new Metadata.Builder()
-                                .setDevice(device)
-                                .setDataOrigin(dataOrigin)
-                                .setClientRecordId("SR" + clientId)
-                                .build(),
-                        Instant.now(),
-                        Instant.now().plusMillis(1000),
-                        10)
-                .build();
-    }
-
-    public static StepsRecord getStepsRecord(String id) {
-        Context context = ApplicationProvider.getApplicationContext();
-        Device device =
-                new Device.Builder().setManufacturer("google").setModel("Pixel").setType(1).build();
-        DataOrigin dataOrigin =
-                new DataOrigin.Builder().setPackageName(context.getPackageName()).build();
-        return new StepsRecord.Builder(
-                        new Metadata.Builder()
-                                .setDevice(device)
-                                .setId(id)
-                                .setDataOrigin(dataOrigin)
-                                .build(),
-                        Instant.now(),
-                        Instant.now().plusMillis(1000),
-                        10)
-                .build();
-    }
-
-    public static HeartRateRecord getHeartRateRecord() {
-        String packageName = ApplicationProvider.getApplicationContext().getPackageName();
-        double clientId = Math.random();
-        return getHeartRateRecord(packageName, clientId);
-    }
-
-    public static HeartRateRecord getHeartRateRecord(String packageName, double clientId) {
-        HeartRateRecord.HeartRateSample heartRateSample =
-                new HeartRateRecord.HeartRateSample(72, Instant.now().plusMillis(100));
-        ArrayList<HeartRateRecord.HeartRateSample> heartRateSamples = new ArrayList<>();
-        heartRateSamples.add(heartRateSample);
-        heartRateSamples.add(heartRateSample);
-        Device device =
-                new Device.Builder().setManufacturer("google").setModel("Pixel").setType(1).build();
-        DataOrigin dataOrigin = new DataOrigin.Builder().setPackageName(packageName).build();
-
-        return new HeartRateRecord.Builder(
-                        new Metadata.Builder()
-                                .setDevice(device)
-                                .setDataOrigin(dataOrigin)
-                                .setClientRecordId("HR" + clientId)
-                                .build(),
-                        Instant.now(),
-                        Instant.now().plusMillis(500),
-                        heartRateSamples)
-                .build();
-    }
-
-    public static HeartRateRecord getHeartRateRecord(int heartRate) {
-        HeartRateRecord.HeartRateSample heartRateSample =
-                new HeartRateRecord.HeartRateSample(heartRate, Instant.now().plusMillis(100));
-        ArrayList<HeartRateRecord.HeartRateSample> heartRateSamples = new ArrayList<>();
-        heartRateSamples.add(heartRateSample);
-        heartRateSamples.add(heartRateSample);
-
-        return new HeartRateRecord.Builder(
-                        new Metadata.Builder().build(),
-                        Instant.now(),
-                        Instant.now().plusMillis(500),
-                        heartRateSamples)
-                .build();
-    }
-
-    public static HeartRateRecord getHeartRateRecord(int heartRate, Instant instant) {
-        HeartRateRecord.HeartRateSample heartRateSample =
-                new HeartRateRecord.HeartRateSample(heartRate, instant);
-        ArrayList<HeartRateRecord.HeartRateSample> heartRateSamples = new ArrayList<>();
-        heartRateSamples.add(heartRateSample);
-        heartRateSamples.add(heartRateSample);
-
-        return new HeartRateRecord.Builder(
-                        new Metadata.Builder().build(),
-                        instant,
-                        instant.plusMillis(1000),
-                        heartRateSamples)
-                .build();
-    }
-
-    public static BasalMetabolicRateRecord getBasalMetabolicRateRecord() {
-        String packageName = ApplicationProvider.getApplicationContext().getPackageName();
-        double clientId = Math.random();
-
-        return getBasalMetabolicRateRecord(packageName, clientId);
-    }
-
-    public static BasalMetabolicRateRecord getBasalMetabolicRateRecord(
-            String packageName, double clientId) {
-        Device device =
-                new Device.Builder()
-                        .setManufacturer("google")
-                        .setModel("Pixel4a")
-                        .setType(2)
-                        .build();
-        DataOrigin dataOrigin = new DataOrigin.Builder().setPackageName(packageName).build();
-        return new BasalMetabolicRateRecord.Builder(
-                        new Metadata.Builder()
-                                .setDevice(device)
-                                .setDataOrigin(dataOrigin)
-                                .setClientRecordId("BMR" + clientId)
-                                .build(),
-                        Instant.now(),
-                        Power.fromWatts(100.0))
-                .build();
-    }
-
-    public static ExerciseSessionRecord getExerciseSessionRecord(
-            String packageName, double clientId, boolean withRoute) {
-        Instant startTime = Instant.now().minusSeconds(3000).truncatedTo(ChronoUnit.MILLIS);
-        Instant endTime = Instant.now();
-        ExerciseSessionRecord.Builder builder =
-                new ExerciseSessionRecord.Builder(
-                                buildSessionMetadata(packageName, clientId),
-                                startTime,
-                                endTime,
-                                ExerciseSessionType.EXERCISE_SESSION_TYPE_OTHER_WORKOUT)
-                        .setEndZoneOffset(ZoneOffset.MAX)
-                        .setStartZoneOffset(ZoneOffset.MIN)
-                        .setNotes("notes")
-                        .setTitle("title");
-
-        if (withRoute) {
-            builder.setRoute(
-                    new ExerciseRoute(
-                            List.of(
-                                    new ExerciseRoute.Location.Builder(startTime, 50., 50.).build(),
-                                    new ExerciseRoute.Location.Builder(
-                                                    startTime.plusSeconds(2), 51., 51.)
-                                            .build())));
-        }
-        return builder.build();
-    }
-
-    public static StepsRecord buildStepsRecord(
-            String startTime, String endTime, int stepsCount, String packageName) {
-        Device device =
-                new Device.Builder().setManufacturer("google").setModel("Pixel").setType(1).build();
-        DataOrigin dataOrigin = new DataOrigin.Builder().setPackageName(packageName).build();
-        return new StepsRecord.Builder(
-                        new Metadata.Builder().setDevice(device).setDataOrigin(dataOrigin).build(),
-                        getInstantTime(startTime),
-                        getInstantTime(endTime),
-                        stepsCount)
-                .build();
-    }
-
-    public static ExerciseSessionRecord buildExerciseSession(
-            String sessionStartTime, String sessionEndTime, Context context) {
-        return new ExerciseSessionRecord.Builder(
-                        new Metadata.Builder()
-                                .setDataOrigin(
-                                        new DataOrigin.Builder()
-                                                .setPackageName(context.getPackageName())
-                                                .build())
-                                .setId("ExerciseSession" + Math.random())
-                                .setClientRecordId("ExerciseSessionClient" + Math.random())
-                                .build(),
-                        getInstantTime(sessionStartTime),
-                        getInstantTime(sessionEndTime),
-                        ExerciseSessionType.EXERCISE_SESSION_TYPE_FOOTBALL_AMERICAN)
-                .build();
-    }
-
-    public static ExerciseSessionRecord buildExerciseSession(
-            String sessionStartTime,
-            String sessionEndTime,
-            String pauseStart,
-            String pauseEnd,
-            Context context) {
-        List<ExerciseSegment> segmentList =
-                List.of(
-                        new ExerciseSegment.Builder(
-                                        getInstantTime(sessionStartTime),
-                                        getInstantTime(pauseStart),
-                                        ExerciseSegmentType.EXERCISE_SEGMENT_TYPE_OTHER_WORKOUT)
-                                .setRepetitionsCount(10)
-                                .build(),
-                        new ExerciseSegment.Builder(
-                                        getInstantTime(pauseStart),
-                                        getInstantTime(pauseEnd),
-                                        ExerciseSegmentType.EXERCISE_SEGMENT_TYPE_PAUSE)
-                                .build());
-
-        if (getInstantTime(sessionEndTime).compareTo(getInstantTime(pauseEnd)) > 0) {
-            segmentList.add(
-                    new ExerciseSegment.Builder(
-                                    getInstantTime(pauseEnd),
-                                    getInstantTime(sessionEndTime),
-                                    ExerciseSegmentType.EXERCISE_SEGMENT_TYPE_OTHER_WORKOUT)
-                            .setRepetitionsCount(10)
-                            .build());
-        }
-
-        return new ExerciseSessionRecord.Builder(
-                        new Metadata.Builder()
-                                .setDataOrigin(
-                                        new DataOrigin.Builder()
-                                                .setPackageName(context.getPackageName())
-                                                .build())
-                                .setId("ExerciseSession" + Math.random())
-                                .setClientRecordId("ExerciseSessionClient" + Math.random())
-                                .build(),
-                        getInstantTime(sessionStartTime),
-                        getInstantTime(sessionEndTime),
-                        ExerciseSessionType.EXERCISE_SESSION_TYPE_FOOTBALL_AMERICAN)
-                .setSegments(segmentList)
-                .build();
-    }
-
-    public static Instant getInstantTime(String time) {
-        return LocalDateTime.parse(
-                        time + " Mon 5/15/2023",
-                        DateTimeFormatter.ofPattern("hh:mm a EEE M/d/uuuu", Locale.US))
-                .atZone(ZoneId.of("America/Toronto"))
-                .toInstant();
-    }
-
     public static <T> AggregateRecordsResponse<T> getAggregateResponse(
             AggregateRecordsRequest<T> request) throws InterruptedException {
         HealthConnectReceiver<AggregateRecordsResponse<T>> receiver =
@@ -637,16 +307,26 @@
 
     public static <T extends Record> List<T> readRecords(ReadRecordsRequest<T> request)
             throws InterruptedException {
-        return readRecords(request, ApplicationProvider.getApplicationContext());
+        return getReadRecordsResponse(request).getRecords();
     }
 
     public static <T extends Record> List<T> readRecords(
             ReadRecordsRequest<T> request, Context context) throws InterruptedException {
+        return getReadRecordsResponse(request, context).getRecords();
+    }
+
+    public static <T extends Record> ReadRecordsResponse<T> getReadRecordsResponse(
+            ReadRecordsRequest<T> request) throws InterruptedException {
+        return getReadRecordsResponse(request, ApplicationProvider.getApplicationContext());
+    }
+
+    public static <T extends Record> ReadRecordsResponse<T> getReadRecordsResponse(
+            ReadRecordsRequest<T> request, Context context) throws InterruptedException {
         assertThat(request.getRecordType()).isNotNull();
         HealthConnectReceiver<ReadRecordsResponse<T>> receiver = new HealthConnectReceiver<>();
         getHealthConnectManager(context)
                 .readRecords(request, Executors.newSingleThreadExecutor(), receiver);
-        return receiver.getResponse().getRecords();
+        return receiver.getResponse();
     }
 
     public static <T extends Record> void assertRecordNotFound(String uuid, Class<T> recordType)
@@ -804,32 +484,6 @@
         }
     }
 
-    public static ExerciseSessionRecord buildExerciseSession() {
-        return buildExerciseSession(buildExerciseRoute(), "Morning training", "rain");
-    }
-
-    public static SleepSessionRecord buildSleepSession() {
-        return new SleepSessionRecord.Builder(
-                        generateMetadata(), SESSION_START_TIME, SESSION_END_TIME)
-                .setNotes("warm")
-                .setTitle("Afternoon nap")
-                .setStages(
-                        List.of(
-                                new SleepSessionRecord.Stage(
-                                        SESSION_START_TIME,
-                                        SESSION_START_TIME.plusSeconds(300),
-                                        SleepSessionRecord.StageType.STAGE_TYPE_SLEEPING_LIGHT),
-                                new SleepSessionRecord.Stage(
-                                        SESSION_START_TIME.plusSeconds(300),
-                                        SESSION_START_TIME.plusSeconds(600),
-                                        SleepSessionRecord.StageType.STAGE_TYPE_SLEEPING_REM),
-                                new SleepSessionRecord.Stage(
-                                        SESSION_START_TIME.plusSeconds(900),
-                                        SESSION_START_TIME.plusSeconds(1200),
-                                        SleepSessionRecord.StageType.STAGE_TYPE_SLEEPING_DEEP)))
-                .build();
-    }
-
     public static void startMigration() throws InterruptedException {
         MigrationReceiver receiver = new MigrationReceiver();
         getHealthConnectManager().startMigration(Executors.newSingleThreadExecutor(), receiver);
@@ -903,121 +557,6 @@
         throw new AssertionError("Record not found with id: " + id);
     }
 
-    public static Metadata generateMetadata() {
-        Context context = ApplicationProvider.getApplicationContext();
-        return new Metadata.Builder()
-                .setDevice(buildDevice())
-                .setId(UUID.randomUUID().toString())
-                .setClientRecordId("clientRecordId" + Math.random())
-                .setDataOrigin(
-                        new DataOrigin.Builder().setPackageName(context.getPackageName()).build())
-                .setDevice(buildDevice())
-                .setRecordingMethod(Metadata.RECORDING_METHOD_UNKNOWN)
-                .build();
-    }
-
-    public static HeartRateRecord getHugeHeartRateRecord() {
-        Device device =
-                new Device.Builder()
-                        .setManufacturer("google")
-                        .setModel("Pixel4a")
-                        .setType(2)
-                        .build();
-        DataOrigin dataOrigin =
-                new DataOrigin.Builder().setPackageName("android.healthconnect.cts").build();
-        Metadata.Builder testMetadataBuilder = new Metadata.Builder();
-        testMetadataBuilder.setDevice(device).setDataOrigin(dataOrigin);
-        testMetadataBuilder.setClientRecordId("HRR" + Math.random());
-        testMetadataBuilder.setRecordingMethod(Metadata.RECORDING_METHOD_ACTIVELY_RECORDED);
-
-        HeartRateRecord.HeartRateSample heartRateRecord =
-                new HeartRateRecord.HeartRateSample(10, Instant.now().plusMillis(100));
-        ArrayList<HeartRateRecord.HeartRateSample> heartRateRecords =
-                new ArrayList<>(Collections.nCopies(85000, heartRateRecord));
-
-        return new HeartRateRecord.Builder(
-                        testMetadataBuilder.build(),
-                        Instant.now(),
-                        Instant.now().plusMillis(500),
-                        heartRateRecords)
-                .build();
-    }
-
-    public static StepsRecord getCompleteStepsRecord() {
-        Device device =
-                new Device.Builder().setManufacturer("google").setModel("Pixel").setType(1).build();
-        DataOrigin dataOrigin =
-                new DataOrigin.Builder().setPackageName("android.healthconnect.cts").build();
-
-        Metadata.Builder testMetadataBuilder = new Metadata.Builder();
-        testMetadataBuilder.setDevice(device).setDataOrigin(dataOrigin);
-        testMetadataBuilder.setClientRecordId("SR" + Math.random());
-        testMetadataBuilder.setRecordingMethod(RECORDING_METHOD_ACTIVELY_RECORDED);
-        Metadata testMetaData = testMetadataBuilder.build();
-        assertThat(testMetaData.getRecordingMethod()).isEqualTo(RECORDING_METHOD_ACTIVELY_RECORDED);
-        return new StepsRecord.Builder(
-                        testMetaData, Instant.now(), Instant.now().plusMillis(1000), 10)
-                .build();
-    }
-
-    public static StepsRecord getStepsRecord_update(
-            Record record, String id, String clientRecordId) {
-        Metadata metadata = record.getMetadata();
-        Metadata metadataWithId =
-                new Metadata.Builder()
-                        .setId(id)
-                        .setClientRecordId(clientRecordId)
-                        .setClientRecordVersion(metadata.getClientRecordVersion())
-                        .setDataOrigin(metadata.getDataOrigin())
-                        .setDevice(metadata.getDevice())
-                        .setLastModifiedTime(metadata.getLastModifiedTime())
-                        .build();
-        return new StepsRecord.Builder(
-                        metadataWithId, Instant.now(), Instant.now().plusMillis(2000), 20)
-                .setStartZoneOffset(ZoneOffset.systemDefault().getRules().getOffset(Instant.now()))
-                .setEndZoneOffset(ZoneOffset.systemDefault().getRules().getOffset(Instant.now()))
-                .build();
-    }
-
-    private static ExerciseSessionRecord buildExerciseSession(
-            ExerciseRoute route, String title, String notes) {
-        return new ExerciseSessionRecord.Builder(
-                        generateMetadata(),
-                        SESSION_START_TIME,
-                        SESSION_END_TIME,
-                        ExerciseSessionType.EXERCISE_SESSION_TYPE_OTHER_WORKOUT)
-                .setRoute(route)
-                .setLaps(
-                        List.of(
-                                new ExerciseLap.Builder(
-                                                SESSION_START_TIME,
-                                                SESSION_START_TIME.plusSeconds(20))
-                                        .setLength(Length.fromMeters(10))
-                                        .build(),
-                                new ExerciseLap.Builder(
-                                                SESSION_END_TIME.minusSeconds(20), SESSION_END_TIME)
-                                        .build()))
-                .setSegments(
-                        List.of(
-                                new ExerciseSegment.Builder(
-                                                SESSION_START_TIME.plusSeconds(1),
-                                                SESSION_START_TIME.plusSeconds(10),
-                                                ExerciseSegmentType
-                                                        .EXERCISE_SEGMENT_TYPE_BENCH_PRESS)
-                                        .build(),
-                                new ExerciseSegment.Builder(
-                                                SESSION_START_TIME.plusSeconds(21),
-                                                SESSION_START_TIME.plusSeconds(124),
-                                                ExerciseSegmentType.EXERCISE_SEGMENT_TYPE_BURPEE)
-                                        .setRepetitionsCount(15)
-                                        .build()))
-                .setEndZoneOffset(ZoneOffset.MAX)
-                .setStartZoneOffset(ZoneOffset.MIN)
-                .setNotes(notes)
-                .setTitle(title)
-                .build();
-    }
-
     public static void populateAndResetExpectedResponseMap(
             HashMap<Class<? extends Record>, RecordTypeInfoTestResponse> expectedResponseMap) {
         expectedResponseMap.put(
@@ -1209,131 +748,6 @@
         receiver.verifyNoExceptionOrThrow();
     }
 
-    public static void grantPermission(String pkgName, String permission) {
-        HealthConnectManager service = getHealthConnectManager();
-        runWithShellPermissionIdentity(
-                () ->
-                        service.getClass()
-                                .getMethod("grantHealthPermission", String.class, String.class)
-                                .invoke(service, pkgName, permission),
-                MANAGE_HEALTH_PERMISSIONS);
-    }
-
-    public static void revokePermission(String pkgName, String permission) {
-        HealthConnectManager service = getHealthConnectManager();
-        runWithShellPermissionIdentity(
-                () ->
-                        service.getClass()
-                                .getMethod(
-                                        "revokeHealthPermission",
-                                        String.class,
-                                        String.class,
-                                        String.class)
-                                .invoke(service, pkgName, permission, null),
-                MANAGE_HEALTH_PERMISSIONS);
-    }
-
-    /**
-     * Utility method to call {@link HealthConnectManager#revokeAllHealthPermissions(String,
-     * String)}.
-     */
-    public static void revokeAllPermissions(String packageName, @Nullable String reason) {
-        HealthConnectManager service = getHealthConnectManager();
-        runWithShellPermissionIdentity(
-                () ->
-                        service.getClass()
-                                .getMethod("revokeAllHealthPermissions", String.class, String.class)
-                                .invoke(service, packageName, reason),
-                MANAGE_HEALTH_PERMISSIONS);
-    }
-
-    /**
-     * Same as {@link #revokeAllPermissions(String, String)} but with a delay to wait for grant time
-     * to be updated.
-     */
-    public static void revokeAllPermissionsWithDelay(String packageName, @Nullable String reason)
-            throws InterruptedException {
-        revokeAllPermissions(packageName, reason);
-        Thread.sleep(500);
-    }
-
-    /**
-     * Utility method to call {@link
-     * HealthConnectManager#getHealthDataHistoricalAccessStartDate(String)}.
-     */
-    public static Instant getHealthDataHistoricalAccessStartDate(String packageName) {
-        HealthConnectManager service = getHealthConnectManager();
-        return (Instant)
-                runWithShellPermissionIdentity(
-                        () ->
-                                service.getClass()
-                                        .getMethod(
-                                                "getHealthDataHistoricalAccessStartDate",
-                                                String.class)
-                                        .invoke(service, packageName),
-                        MANAGE_HEALTH_PERMISSIONS);
-    }
-
-    public static void revokeHealthPermissions(String packageName) {
-        runWithShellPermissionIdentity(() -> revokeHealthPermissionsPrivileged(packageName));
-    }
-
-    private static void revokeHealthPermissionsPrivileged(String packageName)
-            throws PackageManager.NameNotFoundException {
-        final Context targetContext = androidx.test.InstrumentationRegistry.getTargetContext();
-        final PackageManager packageManager = targetContext.getPackageManager();
-        final UserHandle user = targetContext.getUser();
-
-        final PackageInfo packageInfo =
-                packageManager.getPackageInfo(
-                        packageName,
-                        PackageManager.PackageInfoFlags.of(PackageManager.GET_PERMISSIONS));
-
-        final String[] permissions = packageInfo.requestedPermissions;
-        if (permissions == null) {
-            return;
-        }
-
-        for (String permission : permissions) {
-            if (permission.startsWith(HEALTH_PERMISSION_PREFIX)) {
-                packageManager.revokeRuntimePermission(packageName, permission, user);
-            }
-        }
-    }
-
-    public static List<String> getGrantedHealthPermissions(String pkgName) {
-        final PackageInfo pi = getAppPackageInfo(pkgName);
-        final String[] requestedPermissions = pi.requestedPermissions;
-        final int[] requestedPermissionsFlags = pi.requestedPermissionsFlags;
-
-        if (requestedPermissions == null) {
-            return List.of();
-        }
-
-        final List<String> permissions = new ArrayList<>();
-
-        for (int i = 0; i < requestedPermissions.length; i++) {
-            if ((requestedPermissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
-                if (requestedPermissions[i].startsWith(HEALTH_PERMISSION_PREFIX)) {
-                    permissions.add(requestedPermissions[i]);
-                }
-            }
-        }
-
-        return permissions;
-    }
-
-    private static PackageInfo getAppPackageInfo(String pkgName) {
-        final Context targetContext = androidx.test.InstrumentationRegistry.getTargetContext();
-        return runWithShellPermissionIdentity(
-                () ->
-                        targetContext
-                                .getPackageManager()
-                                .getPackageInfo(
-                                        pkgName,
-                                        PackageManager.PackageInfoFlags.of(GET_PERMISSIONS)));
-    }
-
     public static void deleteTestData() throws InterruptedException {
         verifyDeleteRecords(
                 new DeleteUsingFiltersRequest.Builder()
@@ -1349,16 +763,6 @@
                         .build());
     }
 
-    public static void revokeAndThenGrantHealthPermissions(TestApp testApp) {
-        List<String> healthPerms = getGrantedHealthPermissions(testApp.getPackageName());
-
-        revokeHealthPermissions(testApp.getPackageName());
-
-        for (String perm : healthPerms) {
-            grantPermission(testApp.getPackageName(), perm);
-        }
-    }
-
     public static String runShellCommand(String command) throws IOException {
         UiAutomation uiAutomation =
                 androidx.test.platform.app.InstrumentationRegistry.getInstrumentation()
@@ -1383,7 +787,7 @@
     }
 
     @NonNull
-    private static HealthConnectManager getHealthConnectManager() {
+    static HealthConnectManager getHealthConnectManager() {
         return getHealthConnectManager(ApplicationProvider.getApplicationContext());
     }
 
@@ -1393,11 +797,17 @@
     }
 
     public static String getDeviceConfigValue(String key) {
-        return SystemUtil.runShellCommand("device_config get health_fitness " + key);
+        return runWithShellPermissionIdentity(
+                () -> DeviceConfig.getProperty(DeviceConfig.NAMESPACE_HEALTH_FITNESS, key),
+                READ_DEVICE_CONFIG);
     }
 
     public static void setDeviceConfigValue(String key, String value) {
-        SystemUtil.runShellCommand("device_config put health_fitness " + key + " " + value);
+        runWithShellPermissionIdentity(
+                () ->
+                        DeviceConfig.setProperty(
+                                DeviceConfig.NAMESPACE_HEALTH_FITNESS, key, value, false),
+                WRITE_ALLOWLISTED_DEVICE_CONFIG);
     }
 
     public static void sendCommandToTestAppReceiver(Context context, String action) {
@@ -1510,6 +920,19 @@
         }
     }
 
+    public static boolean isHardwareSupported() {
+        return isHardwareSupported(ApplicationProvider.getApplicationContext());
+    }
+
+    /** returns true if the hardware is supported by HealthConnect. */
+    public static boolean isHardwareSupported(Context context) {
+        PackageManager pm = context.getPackageManager();
+        return (!pm.hasSystemFeature(PackageManager.FEATURE_EMBEDDED)
+                && !pm.hasSystemFeature(PackageManager.FEATURE_WATCH)
+                && !pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
+                && !pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE));
+    }
+
     /** Gets the priority list after getting the MANAGE_HEALTH_DATA permission. */
     public static FetchDataOriginsPriorityOrderResponse getPriorityWithManageHealthDataPermission(
             int permissionCategory) throws InterruptedException {
@@ -1564,6 +987,56 @@
         return response.get();
     }
 
+    /**
+     * Marks apps with any granted health permissions as connected to HC.
+     *
+     * <p>Test apps in CTS get their permissions auto granted without going through the HC
+     * connection flow which prevents the HC service from recording the app info in the database.
+     *
+     * <p>This method calls "getCurrentPriority" API behind the scenes which has a side effect of
+     * adding all the apps on the device with at least one health permission granted to the
+     * database.
+     */
+    public static void connectAppsWithGrantedPermissions() {
+        try {
+            getPriorityWithManageHealthDataPermission(1);
+        } catch (InterruptedException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+
+    /** Zips given id and records lists to create a list of {@link RecordIdFilter}. */
+    public static List<RecordIdFilter> getRecordIdFilters(
+            List<String> recordIds, List<Record> records) {
+        return IntStream.range(0, recordIds.size())
+                .mapToObj(
+                        i -> {
+                            Class<? extends Record> recordClass = records.get(i).getClass();
+                            String id = recordIds.get(i);
+                            return RecordIdFilter.fromId(recordClass, id);
+                        })
+                .toList();
+    }
+
+    /** Creates an {@link Instant} representing the given local time yesterday at UTC. */
+    public static Instant yesterdayAt(String localTime) {
+        return LocalTime.parse(localTime)
+                .atDate(LocalDate.now().minusDays(1))
+                .toInstant(ZoneOffset.UTC);
+    }
+
+    public static List<String> insertStepsRecordViaTestApp(
+            Context context, Instant startTime, Instant endTime, long value) {
+        Bundle bundle = new Bundle();
+        bundle.putLongArray(EXTRA_TIMES, new long[] {startTime.toEpochMilli()});
+        bundle.putLongArray(EXTRA_END_TIMES, new long[] {endTime.toEpochMilli()});
+        bundle.putLongArray(EXTRA_RECORD_VALUES, new long[] {value});
+        android.healthconnect.cts.utils.TestReceiver.reset();
+        sendCommandToTestAppReceiver(context, ACTION_INSERT_STEPS_RECORDS, bundle);
+        return android.healthconnect.cts.utils.TestReceiver.getResult()
+                .getStringArrayList(EXTRA_RECORD_IDS);
+    }
+
     public static final class RecordAndIdentifier {
         private final int mId;
         private final Record mRecordClass;
@@ -1609,24 +1082,6 @@
         }
     }
 
-    public static class RecordTypeAndRecordIds implements Serializable {
-        private String mRecordType;
-        private List<String> mRecordIds;
-
-        public RecordTypeAndRecordIds(String recordType, List<String> ids) {
-            mRecordType = recordType;
-            mRecordIds = ids;
-        }
-
-        public String getRecordType() {
-            return mRecordType;
-        }
-
-        public List<String> getRecordIds() {
-            return mRecordIds;
-        }
-    }
-
     private static class TestReceiver<T, E extends RuntimeException>
             implements OutcomeReceiver<T, E> {
         private final CountDownLatch mLatch = new CountDownLatch(1);
diff --git a/tests/integrationtests/TestApp/src/android/healthconnect/test/app/BlockingOutcomeReceiver.java b/tests/integrationtests/TestApp/src/android/healthconnect/test/app/BlockingOutcomeReceiver.java
index 16a723f..049c06b 100644
--- a/tests/integrationtests/TestApp/src/android/healthconnect/test/app/BlockingOutcomeReceiver.java
+++ b/tests/integrationtests/TestApp/src/android/healthconnect/test/app/BlockingOutcomeReceiver.java
@@ -16,18 +16,17 @@
 
 package android.healthconnect.test.app;
 
-import android.health.connect.HealthConnectException;
 import android.os.OutcomeReceiver;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
-public final class BlockingOutcomeReceiver<T>
-        implements OutcomeReceiver<T, HealthConnectException> {
+/** A blocking implementation of {@link OutcomeReceiver} that allows waiting for responses. */
+public class BlockingOutcomeReceiver<T, E extends Throwable> implements OutcomeReceiver<T, E> {
 
     private final CountDownLatch mLatch = new CountDownLatch(1);
     private T mResult;
-    private HealthConnectException mError;
+    private E mError;
 
     @Override
     public void onResult(T result) {
@@ -36,17 +35,28 @@
     }
 
     @Override
-    public void onError(HealthConnectException error) {
+    public void onError(E error) {
         mError = error;
         mLatch.countDown();
     }
 
-    public T getResult() throws HealthConnectException {
-        await();
+    /** Waits for a response and returns the result if successful, or throws the error if failed. */
+    public T getResult() throws E {
+        awaitSuccess();
         return mResult;
     }
 
-    public HealthConnectException getError() {
+    /** Waits for a response, throws the error if failed. */
+    public void awaitSuccess() throws E {
+        await();
+
+        if (mError != null) {
+            throw mError;
+        }
+    }
+
+    /** Waits for a response and returns the error if failed, or {@code null} if successful. */
+    public E getError() {
         await();
         return mError;
     }
diff --git a/tests/integrationtests/TestApp/src/android/healthconnect/test/app/DefaultOutcomeReceiver.java b/tests/integrationtests/TestApp/src/android/healthconnect/test/app/DefaultOutcomeReceiver.java
new file mode 100644
index 0000000..d3edfb0
--- /dev/null
+++ b/tests/integrationtests/TestApp/src/android/healthconnect/test/app/DefaultOutcomeReceiver.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.test.app;
+
+import android.health.connect.HealthConnectException;
+
+/**
+ * A predefined {@link BlockingOutcomeReceiver} with the error type {@link HealthConnectException}.
+ * Can be used instead of {@link BlockingOutcomeReceiver} to avoid specifying the error type every
+ * time.
+ */
+public final class DefaultOutcomeReceiver<T>
+        extends BlockingOutcomeReceiver<T, HealthConnectException> {}
diff --git a/tests/integrationtests/TestApp/src/android/healthconnect/test/app/TestAppReceiver.java b/tests/integrationtests/TestApp/src/android/healthconnect/test/app/TestAppReceiver.java
index 1253b64..98c1cd2 100644
--- a/tests/integrationtests/TestApp/src/android/healthconnect/test/app/TestAppReceiver.java
+++ b/tests/integrationtests/TestApp/src/android/healthconnect/test/app/TestAppReceiver.java
@@ -110,22 +110,22 @@
     }
 
     private static void insertStepsRecords(Context context, Intent intent) {
-        BlockingOutcomeReceiver<InsertRecordsResponse> outcome = new BlockingOutcomeReceiver<>();
+        DefaultOutcomeReceiver<InsertRecordsResponse> outcome = new DefaultOutcomeReceiver<>();
         getHealthConnectManager(context)
                 .insertRecords(createStepsRecords(intent), newSingleThreadExecutor(), outcome);
         sendInsertRecordsResult(context, intent, outcome);
     }
 
     private static void insertWeightRecords(Context context, Intent intent) {
-        BlockingOutcomeReceiver<InsertRecordsResponse> outcome = new BlockingOutcomeReceiver<>();
+        DefaultOutcomeReceiver<InsertRecordsResponse> outcome = new DefaultOutcomeReceiver<>();
         getHealthConnectManager(context)
                 .insertRecords(createWeightRecords(intent), newSingleThreadExecutor(), outcome);
         sendInsertRecordsResult(context, intent, outcome);
     }
 
     private void readRecordsForOtherApp(Context context, Intent intent) {
-        final BlockingOutcomeReceiver<ReadRecordsResponse<ActiveCaloriesBurnedRecord>> outcome =
-                new BlockingOutcomeReceiver<>();
+        DefaultOutcomeReceiver<ReadRecordsResponse<ActiveCaloriesBurnedRecord>> outcome =
+                new DefaultOutcomeReceiver<>();
 
         getHealthConnectManager(context)
                 .readRecords(
@@ -143,8 +143,8 @@
     }
 
     private void aggregate(Context context, Intent intent) {
-        final BlockingOutcomeReceiver<AggregateRecordsResponse<Energy>> outcome =
-                new BlockingOutcomeReceiver<>();
+        DefaultOutcomeReceiver<AggregateRecordsResponse<Energy>> outcome =
+                new DefaultOutcomeReceiver<>();
 
         getHealthConnectManager(context)
                 .aggregate(
@@ -162,8 +162,7 @@
     }
 
     private void getChangeLogToken(Context context, Intent intent) {
-        final BlockingOutcomeReceiver<ChangeLogTokenResponse> outcome =
-                new BlockingOutcomeReceiver<>();
+        DefaultOutcomeReceiver<ChangeLogTokenResponse> outcome = new DefaultOutcomeReceiver<>();
 
         getHealthConnectManager(context)
                 .getChangeLogToken(
@@ -185,7 +184,7 @@
 
     private void getChangeLogs(Context context, Intent intent) {
         String token = intent.getStringExtra(EXTRA_TOKEN);
-        final BlockingOutcomeReceiver<ChangeLogsResponse> outcome = new BlockingOutcomeReceiver<>();
+        DefaultOutcomeReceiver<ChangeLogsResponse> outcome = new DefaultOutcomeReceiver<>();
 
         getHealthConnectManager(context)
                 .getChangeLogs(
@@ -203,7 +202,7 @@
     private static void sendReadRecordsResult(
             Context context,
             Intent intent,
-            BlockingOutcomeReceiver<? extends ReadRecordsResponse<?>> outcome) {
+            DefaultOutcomeReceiver<? extends ReadRecordsResponse<?>> outcome) {
         final HealthConnectException error = outcome.getError();
         if (error != null) {
             sendError(context, intent, error);
@@ -218,7 +217,7 @@
     private static void sendInsertRecordsResult(
             Context context,
             Intent intent,
-            BlockingOutcomeReceiver<? extends InsertRecordsResponse> outcome) {
+            DefaultOutcomeReceiver<? extends InsertRecordsResponse> outcome) {
         final HealthConnectException error = outcome.getError();
         if (error != null) {
             sendError(context, intent, error);
@@ -239,7 +238,7 @@
     }
 
     private static void sendResult(
-            Context context, Intent intent, BlockingOutcomeReceiver<?> outcomeReceiver) {
+            Context context, Intent intent, DefaultOutcomeReceiver<?> outcomeReceiver) {
         final HealthConnectException error = outcomeReceiver.getError();
         if (error != null) {
             sendError(context, intent, error);
diff --git a/tests/integrationtests/src/android/healthconnect/tests/IntegrationTestUtils.java b/tests/integrationtests/src/android/healthconnect/tests/IntegrationTestUtils.java
new file mode 100644
index 0000000..54c31d3
--- /dev/null
+++ b/tests/integrationtests/src/android/healthconnect/tests/IntegrationTestUtils.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 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 android.healthconnect.tests;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static java.util.concurrent.Executors.newSingleThreadExecutor;
+
+import android.content.Context;
+import android.health.connect.HealthConnectManager;
+import android.health.connect.migration.MigrationEntity;
+import android.health.connect.migration.MigrationException;
+import android.healthconnect.test.app.BlockingOutcomeReceiver;
+import android.os.OutcomeReceiver;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import java.util.List;
+import java.util.concurrent.Executor;
+
+/** Utils for permission tests. */
+public final class IntegrationTestUtils {
+
+    private IntegrationTestUtils() {}
+
+    /**
+     * Calls {@link HealthConnectManager#startMigration(Executor, OutcomeReceiver)} and waits for
+     * the call to finish.
+     */
+    public static void startMigration() {
+        BlockingOutcomeReceiver<Void, MigrationException> outcome = new BlockingOutcomeReceiver<>();
+        getHealthConnectManager().startMigration(newSingleThreadExecutor(), outcome);
+        outcome.awaitSuccess();
+    }
+
+    /**
+     * Calls {@link HealthConnectManager#writeMigrationData(List, Executor, OutcomeReceiver)} and
+     * waits for the call to finish.
+     */
+    public static void writeMigrationData(List<MigrationEntity> entities) {
+        BlockingOutcomeReceiver<Void, MigrationException> outcome = new BlockingOutcomeReceiver<>();
+        getHealthConnectManager().writeMigrationData(entities, newSingleThreadExecutor(), outcome);
+        outcome.awaitSuccess();
+    }
+
+    /**
+     * Calls {@link HealthConnectManager#finishMigration(Executor, OutcomeReceiver)} and waits for
+     * the call to finish.
+     */
+    public static void finishMigration() {
+        BlockingOutcomeReceiver<Void, MigrationException> outcome = new BlockingOutcomeReceiver<>();
+        getHealthConnectManager().finishMigration(newSingleThreadExecutor(), outcome);
+        outcome.awaitSuccess();
+    }
+
+    private static HealthConnectManager getHealthConnectManager() {
+        Context context = ApplicationProvider.getApplicationContext();
+        HealthConnectManager service = context.getSystemService(HealthConnectManager.class);
+        assertThat(service).isNotNull();
+
+        return service;
+    }
+}
diff --git a/tests/integrationtests/src/android/healthconnect/tests/backgroundread/BackgroundReadTest.java b/tests/integrationtests/src/android/healthconnect/tests/backgroundread/BackgroundReadTest.java
index fee1f1e..576fa0d 100644
--- a/tests/integrationtests/src/android/healthconnect/tests/backgroundread/BackgroundReadTest.java
+++ b/tests/integrationtests/src/android/healthconnect/tests/backgroundread/BackgroundReadTest.java
@@ -42,8 +42,10 @@
 import android.health.connect.datatypes.ActiveCaloriesBurnedRecord;
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.units.Energy;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.healthconnect.cts.utils.TestReceiver;
-import android.healthconnect.test.app.BlockingOutcomeReceiver;
+import android.healthconnect.cts.utils.TestUtils;
+import android.healthconnect.test.app.DefaultOutcomeReceiver;
 import android.os.Bundle;
 
 import androidx.test.platform.app.InstrumentationRegistry;
@@ -51,6 +53,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -69,6 +72,11 @@
     private HealthConnectManager mManager;
     private String mInitialFeatureFlagValue;
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
@@ -112,16 +120,16 @@
     }
 
     private void insertRecords() {
-        final BlockingOutcomeReceiver<InsertRecordsResponse> outcomeReceiver =
-                new BlockingOutcomeReceiver<>();
+        DefaultOutcomeReceiver<InsertRecordsResponse> outcomeReceiver =
+                new DefaultOutcomeReceiver<>();
 
         mManager.insertRecords(
                 List.of(
                         new ActiveCaloriesBurnedRecord.Builder(
-                                        new Metadata.Builder().build(),
-                                        Instant.now().minusSeconds(60),
-                                        Instant.now(),
-                                        Energy.fromCalories(100.0))
+                                new Metadata.Builder().build(),
+                                Instant.now().minusSeconds(60),
+                                Instant.now(),
+                                Energy.fromCalories(100.0))
                                 .build()),
                 Executors.newSingleThreadExecutor(),
                 outcomeReceiver);
diff --git a/tests/integrationtests/src/android/healthconnect/tests/backuprestore/BackupRestoreApiTest.java b/tests/integrationtests/src/android/healthconnect/tests/backuprestore/BackupRestoreApiTest.java
index 8bbdbd9..f34f799 100644
--- a/tests/integrationtests/src/android/healthconnect/tests/backuprestore/BackupRestoreApiTest.java
+++ b/tests/integrationtests/src/android/healthconnect/tests/backuprestore/BackupRestoreApiTest.java
@@ -36,6 +36,8 @@
 import android.health.connect.datatypes.HeightRecord;
 import android.health.connect.datatypes.Record;
 import android.health.connect.restore.StageRemoteDataException;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
 import android.healthconnect.integrationtests.backuprestore.R;
 import android.os.FileUtils;
 import android.os.OutcomeReceiver;
@@ -49,6 +51,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -70,6 +73,11 @@
     private Context mContext;
     private HealthConnectManager mService;
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
diff --git a/tests/integrationtests/src/android/healthconnect/tests/backuprestore/BackupRestoreE2ETest.java b/tests/integrationtests/src/android/healthconnect/tests/backuprestore/BackupRestoreE2ETest.java
index 999cd0d..86dd321 100644
--- a/tests/integrationtests/src/android/healthconnect/tests/backuprestore/BackupRestoreE2ETest.java
+++ b/tests/integrationtests/src/android/healthconnect/tests/backuprestore/BackupRestoreE2ETest.java
@@ -16,14 +16,14 @@
 
 package android.healthconnect.tests.backuprestore;
 
+import static android.healthconnect.cts.utils.PermissionHelper.getHealthDataHistoricalAccessStartDate;
+import static android.healthconnect.cts.utils.PermissionHelper.grantPermission;
+import static android.healthconnect.cts.utils.PermissionHelper.revokeAllPermissions;
+import static android.healthconnect.cts.utils.PermissionHelper.revokeAllPermissionsWithDelay;
 import static android.healthconnect.cts.utils.TestUtils.deleteAllStagedRemoteData;
 import static android.healthconnect.cts.utils.TestUtils.getHealthConnectDataRestoreState;
-import static android.healthconnect.cts.utils.TestUtils.getHealthDataHistoricalAccessStartDate;
-import static android.healthconnect.cts.utils.TestUtils.grantPermission;
 import static android.healthconnect.cts.utils.TestUtils.insertRecords;
 import static android.healthconnect.cts.utils.TestUtils.readRecords;
-import static android.healthconnect.cts.utils.TestUtils.revokeAllPermissions;
-import static android.healthconnect.cts.utils.TestUtils.revokeAllPermissionsWithDelay;
 import static android.healthconnect.cts.utils.TestUtils.verifyDeleteRecords;
 
 import static com.android.compatibility.common.util.BackupUtils.LOCAL_TRANSPORT_TOKEN;
@@ -43,6 +43,7 @@
 import android.health.connect.datatypes.Metadata;
 import android.health.connect.datatypes.Record;
 import android.health.connect.datatypes.units.Energy;
+import android.healthconnect.cts.utils.TestUtils;
 import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
 import android.platform.test.annotations.AppModeFull;
@@ -98,6 +99,9 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+        if (!TestUtils.isHardwareSupported()) {
+            return;
+        }
         mBackupRestoreApkPackageName = getBackupRestoreApkPackageName();
         // enable backup on the test device
         mBackupUtils.enableBackup(true);
@@ -117,6 +121,9 @@
 
     public void testBackupThenRestore_over2000Records_expectDataIsRestoredCorrectly()
             throws Exception {
+        if (!TestUtils.isHardwareSupported()) {
+            return;
+        }
         int numOfRecords = 2050;
         List<Record> insertedRecords =
                 insertRecordsWithChunking(
@@ -137,6 +144,9 @@
     public void
             testPermissionsControllerIsRestoredBeforeHCRestore_expectGrantTimeIsRestoredCorrectly()
                     throws Exception {
+        if (!TestUtils.isHardwareSupported()) {
+            return;
+        }
         // revoke all permissions for both test apps to remove all stored grant time as setup step
         revokeAllPermissionsWithDelay(TEST_APP_1_PACKAGE_NAME, "");
         revokeAllPermissionsWithDelay(TEST_APP_2_PACKAGE_NAME, "");
diff --git a/tests/integrationtests/src/android/healthconnect/tests/migration/HealthConnectPermissionsMigrationTest.java b/tests/integrationtests/src/android/healthconnect/tests/migration/HealthConnectPermissionsMigrationTest.java
index e4a3b63..5f5153e 100644
--- a/tests/integrationtests/src/android/healthconnect/tests/migration/HealthConnectPermissionsMigrationTest.java
+++ b/tests/integrationtests/src/android/healthconnect/tests/migration/HealthConnectPermissionsMigrationTest.java
@@ -27,32 +27,28 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.junit.Assume.assumeFalse;
-
 import android.Manifest;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.health.connect.HealthConnectManager;
 import android.health.connect.migration.MigrationEntity;
-import android.health.connect.migration.MigrationException;
 import android.health.connect.migration.PermissionMigrationPayload;
-import android.healthconnect.tests.permissions.PermissionsTestUtils;
-import android.os.OutcomeReceiver;
-import android.util.Log;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
+import android.healthconnect.tests.IntegrationTestUtils;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import java.time.Instant;
 import java.time.Period;
 import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicReference;
 
 /** Integration tests for Health Connect permissions migration. */
@@ -64,9 +60,13 @@
     private Context mContext;
     private HealthConnectManager mHealthConnectManager;
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws Exception {
-        assumeFalse(isHardwareAutomotive());
         mContext = InstrumentationRegistry.getTargetContext();
         mHealthConnectManager = mContext.getSystemService(HealthConnectManager.class);
         revokeAllHealthPermissions(DEFAULT_APP_PACKAGE, null);
@@ -112,33 +112,17 @@
         return readGrantTime.get();
     }
 
-    private void migrate(MigrationEntity... entities) throws InterruptedException {
+    private void migrate(MigrationEntity... entities) {
         runWithShellPermissionIdentity(
-                PermissionsTestUtils::startMigration,
+                IntegrationTestUtils::startMigration,
                 Manifest.permission.MIGRATE_HEALTH_CONNECT_DATA);
 
         runWithShellPermissionIdentity(
-                () -> {
-                    CountDownLatch latch = new CountDownLatch(1);
-                    mHealthConnectManager.writeMigrationData(
-                            List.of(entities),
-                            Executors.newSingleThreadExecutor(),
-                            new OutcomeReceiver<>() {
-                                @Override
-                                public void onResult(Void result) {
-                                    latch.countDown();
-                                }
-
-                                @Override
-                                public void onError(MigrationException exception) {
-                                    Log.e(TAG, exception.getMessage());
-                                }
-                            });
-                },
+                () -> IntegrationTestUtils.writeMigrationData(List.of(entities)),
                 Manifest.permission.MIGRATE_HEALTH_CONNECT_DATA);
 
         runWithShellPermissionIdentity(
-                PermissionsTestUtils::finishMigration,
+                IntegrationTestUtils::finishMigration,
                 Manifest.permission.MIGRATE_HEALTH_CONNECT_DATA);
     }
 
diff --git a/tests/integrationtests/src/android/healthconnect/tests/permissions/GrantTimeIntegrationTest.java b/tests/integrationtests/src/android/healthconnect/tests/permissions/GrantTimeIntegrationTest.java
index 0290cfd..f4a3485 100644
--- a/tests/integrationtests/src/android/healthconnect/tests/permissions/GrantTimeIntegrationTest.java
+++ b/tests/integrationtests/src/android/healthconnect/tests/permissions/GrantTimeIntegrationTest.java
@@ -29,11 +29,14 @@
 import android.content.Context;
 import android.health.connect.HealthConnectManager;
 import android.health.connect.HealthPermissions;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -58,6 +61,11 @@
     private Context mContext;
     private HealthConnectManager mHealthConnectManager;
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
diff --git a/tests/integrationtests/src/android/healthconnect/tests/permissions/HealthConnectWithManagePermissionsTest.java b/tests/integrationtests/src/android/healthconnect/tests/permissions/HealthConnectWithManagePermissionsTest.java
index 073bb16..6018f8c 100644
--- a/tests/integrationtests/src/android/healthconnect/tests/permissions/HealthConnectWithManagePermissionsTest.java
+++ b/tests/integrationtests/src/android/healthconnect/tests/permissions/HealthConnectWithManagePermissionsTest.java
@@ -32,12 +32,16 @@
 import android.content.pm.PackageManager;
 import android.health.connect.HealthConnectManager;
 import android.health.connect.HealthPermissions;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
+import android.healthconnect.tests.IntegrationTestUtils;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -76,6 +80,11 @@
     private Context mContext;
     private HealthConnectManager mHealthConnectManager;
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
@@ -435,7 +444,7 @@
     @Test
     public void testPermissionApis_migrationInProgress_apisBlocked() throws Exception {
         runWithShellPermissionIdentity(
-                PermissionsTestUtils::startMigration,
+                IntegrationTestUtils::startMigration,
                 Manifest.permission.MIGRATE_HEALTH_CONNECT_DATA);
 
         // Grant permission
@@ -451,7 +460,7 @@
 
         // Revoke permission
         runWithShellPermissionIdentity(
-                PermissionsTestUtils::startMigration,
+                IntegrationTestUtils::startMigration,
                 Manifest.permission.MIGRATE_HEALTH_CONNECT_DATA);
 
         grantPermissionViaPackageManager(DEFAULT_APP_PACKAGE, DEFAULT_PERM);
@@ -492,7 +501,7 @@
                                 DEFAULT_APP_PACKAGE, List.of(DEFAULT_PERM, DEFAULT_PERM_2)));
 
         runWithShellPermissionIdentity(
-                PermissionsTestUtils::finishMigration,
+                IntegrationTestUtils::finishMigration,
                 Manifest.permission.MIGRATE_HEALTH_CONNECT_DATA);
         assertPermGrantedForApp(DEFAULT_APP_PACKAGE, DEFAULT_PERM);
     }
diff --git a/tests/integrationtests/src/android/healthconnect/tests/permissions/HealthConnectWithoutManagePermissionsTest.java b/tests/integrationtests/src/android/healthconnect/tests/permissions/HealthConnectWithoutManagePermissionsTest.java
index 4807520..d6b30b4 100644
--- a/tests/integrationtests/src/android/healthconnect/tests/permissions/HealthConnectWithoutManagePermissionsTest.java
+++ b/tests/integrationtests/src/android/healthconnect/tests/permissions/HealthConnectWithoutManagePermissionsTest.java
@@ -22,11 +22,14 @@
 import android.content.Context;
 import android.health.connect.HealthConnectManager;
 import android.health.connect.HealthPermissions;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
+import android.healthconnect.cts.utils.TestUtils;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -50,6 +53,11 @@
     private Context mContext;
     private HealthConnectManager mHealthConnectManager;
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    TestUtils::isHardwareSupported, "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
diff --git a/tests/integrationtests/src/android/healthconnect/tests/permissions/PermissionsTestUtils.java b/tests/integrationtests/src/android/healthconnect/tests/permissions/PermissionsTestUtils.java
deleted file mode 100644
index b581932..0000000
--- a/tests/integrationtests/src/android/healthconnect/tests/permissions/PermissionsTestUtils.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2023 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 android.healthconnect.tests.permissions;
-
-import static com.google.common.truth.Truth.assertThat;
-
-
-import android.content.Context;
-import android.health.connect.HealthConnectManager;
-import android.health.connect.migration.MigrationException;
-import android.os.OutcomeReceiver;
-import android.util.Log;
-
-import androidx.test.core.app.ApplicationProvider;
-
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
-
-public class PermissionsTestUtils {
-    private static final String TAG = "HCPermissionsTestUtils";
-
-    public static void startMigration() throws InterruptedException {
-        Context context = ApplicationProvider.getApplicationContext();
-        CountDownLatch latch = new CountDownLatch(1);
-
-        HealthConnectManager service = context.getSystemService(HealthConnectManager.class);
-        assertThat(service).isNotNull();
-        service.startMigration(
-                Executors.newSingleThreadExecutor(),
-                new OutcomeReceiver<Void, MigrationException>() {
-                    @Override
-                    public void onResult(Void result) {
-                        latch.countDown();
-                    }
-
-                    @Override
-                    public void onError(MigrationException exception) {
-                        Log.e(TAG, exception.getMessage());
-                    }
-                });
-        assertThat(latch.await(3, TimeUnit.SECONDS)).isTrue();
-    }
-
-    public static void finishMigration() throws InterruptedException {
-        Context context = ApplicationProvider.getApplicationContext();
-        CountDownLatch latch = new CountDownLatch(1);
-
-        HealthConnectManager service = context.getSystemService(HealthConnectManager.class);
-        assertThat(service).isNotNull();
-        service.finishMigration(
-                Executors.newSingleThreadExecutor(),
-                new OutcomeReceiver<Void, MigrationException>() {
-
-                    @Override
-                    public void onResult(Void result) {
-                        latch.countDown();
-                    }
-
-                    @Override
-                    public void onError(MigrationException exception) {
-                        Log.e(TAG, exception.getMessage());
-                    }
-                });
-        assertThat(latch.await(3, TimeUnit.SECONDS)).isTrue();
-    }
-}
diff --git a/tests/unittests/Android.bp b/tests/unittests/Android.bp
index 23d2c18..0e18283 100644
--- a/tests/unittests/Android.bp
+++ b/tests/unittests/Android.bp
@@ -38,6 +38,7 @@
         "truth-prebuilt",
         "services.core",
         "androidx.test.ext.truth",
+        "cts-healthconnect-utils",
     ],
     jni_libs: [
         // Required for ExtendedMockito
diff --git a/tests/unittests/src/android/healthconnect/HealthPermissionsTest.java b/tests/unittests/src/android/healthconnect/HealthPermissionsTest.java
index 0f92754..c9aef37 100644
--- a/tests/unittests/src/android/healthconnect/HealthPermissionsTest.java
+++ b/tests/unittests/src/android/healthconnect/HealthPermissionsTest.java
@@ -61,7 +61,7 @@
                     HealthPermissions.READ_DISTANCE,
                     HealthPermissions.READ_ELEVATION_GAINED,
                     HealthPermissions.READ_EXERCISE,
-                    HealthPermissions.READ_EXERCISE_ROUTES_ALL,
+                    HealthPermissions.READ_EXERCISE_ROUTES,
                     HealthPermissions.READ_FLOORS_CLIMBED,
                     HealthPermissions.READ_STEPS,
                     HealthPermissions.READ_TOTAL_CALORIES_BURNED,
@@ -93,6 +93,7 @@
                     HealthPermissions.READ_OXYGEN_SATURATION,
                     HealthPermissions.READ_RESPIRATORY_RATE,
                     HealthPermissions.READ_RESTING_HEART_RATE,
+                    HealthPermissions.READ_SKIN_TEMPERATURE,
                     HealthPermissions.WRITE_ACTIVE_CALORIES_BURNED,
                     HealthPermissions.WRITE_DISTANCE,
                     HealthPermissions.WRITE_ELEVATION_GAINED,
@@ -128,7 +129,8 @@
                     HealthPermissions.WRITE_HEART_RATE_VARIABILITY,
                     HealthPermissions.WRITE_OXYGEN_SATURATION,
                     HealthPermissions.WRITE_RESPIRATORY_RATE,
-                    HealthPermissions.WRITE_RESTING_HEART_RATE);
+                    HealthPermissions.WRITE_RESTING_HEART_RATE,
+                    HealthPermissions.WRITE_SKIN_TEMPERATURE);
     private PackageManager mPackageManager;
     private Context mContext;
     @Mock private PackageInfo mPackageInfo1;
diff --git a/tests/unittests/src/com/android/server/healthconnect/HealthConnectServiceImplTest.java b/tests/unittests/src/com/android/server/healthconnect/HealthConnectServiceImplTest.java
index 5c26019..d4dcb12 100644
--- a/tests/unittests/src/com/android/server/healthconnect/HealthConnectServiceImplTest.java
+++ b/tests/unittests/src/com/android/server/healthconnect/HealthConnectServiceImplTest.java
@@ -49,6 +49,7 @@
 import android.health.connect.migration.MigrationEntityParcel;
 import android.health.connect.migration.MigrationException;
 import android.health.connect.restore.StageRemoteDataRequest;
+import android.healthconnect.cts.utils.AssumptionCheckerRule;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
@@ -173,6 +174,12 @@
     private UserHandle mUserHandle;
     private File mMockDataDirectory;
 
+    @Rule
+    public AssumptionCheckerRule mSupportedHardwareRule =
+            new AssumptionCheckerRule(
+                    android.healthconnect.cts.utils.TestUtils::isHardwareSupported,
+                    "Tests should run on supported hardware only.");
+
     @Before
     public void setUp() throws Exception {
         when(UserHandle.of(anyInt())).thenCallRealMethod();
diff --git a/tests/unittests/src/com/android/server/healthconnect/backuprestore/BackupRestoreTest.java b/tests/unittests/src/com/android/server/healthconnect/backuprestore/BackupRestoreTest.java
index e0e444a..05ecc33 100644
--- a/tests/unittests/src/com/android/server/healthconnect/backuprestore/BackupRestoreTest.java
+++ b/tests/unittests/src/com/android/server/healthconnect/backuprestore/BackupRestoreTest.java
@@ -27,13 +27,17 @@
 import static com.android.server.healthconnect.backuprestore.BackupRestore.BackupRestoreJobService.EXTRA_JOB_NAME_KEY;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_DOWNLOAD_STATE_KEY;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_DOWNLOAD_TIMEOUT_CANCELLED_KEY;
+import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_DOWNLOAD_TIMEOUT_INTERVAL_MILLIS;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_DOWNLOAD_TIMEOUT_KEY;
+import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_MERGING_RETRY_DELAY_MILLIS;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_MERGING_RETRY_KEY;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_MERGING_TIMEOUT_CANCELLED_KEY;
+import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_MERGING_TIMEOUT_INTERVAL_MILLIS;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_MERGING_TIMEOUT_KEY;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_RESTORE_ERROR_KEY;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_RESTORE_STATE_KEY;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_STAGING_TIMEOUT_CANCELLED_KEY;
+import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_STAGING_TIMEOUT_INTERVAL_MILLIS;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.DATA_STAGING_TIMEOUT_KEY;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.INTERNAL_RESTORE_STATE_MERGING_DONE_OLD_CODE;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.INTERNAL_RESTORE_STATE_MERGING_DONE;
@@ -41,6 +45,7 @@
 import static com.android.server.healthconnect.backuprestore.BackupRestore.INTERNAL_RESTORE_STATE_STAGING_DONE;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.INTERNAL_RESTORE_STATE_STAGING_IN_PROGRESS;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.INTERNAL_RESTORE_STATE_WAITING_FOR_STAGING;
+import static com.android.server.healthconnect.backuprestore.BackupRestore.MINIMUM_LATENCY_WINDOW_MILLIS;
 import static com.android.server.healthconnect.backuprestore.BackupRestore.STAGED_DATABASE_NAME;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -48,10 +53,8 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -222,8 +225,6 @@
         @HealthConnectManager.DataDownloadState int testDownloadStateSet = DATA_DOWNLOAD_STARTED;
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_DOWNLOAD_STATE_KEY, String.valueOf(testDownloadStateSet));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_DOWNLOAD_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         mBackupRestore.updateDataDownloadState(testDownloadStateSet);
 
@@ -246,8 +247,6 @@
         @HealthConnectManager.DataDownloadState int testDownloadStateSet = DATA_DOWNLOAD_RETRY;
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_DOWNLOAD_STATE_KEY, String.valueOf(testDownloadStateSet));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_DOWNLOAD_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         mBackupRestore.updateDataDownloadState(testDownloadStateSet);
         ExtendedMockito.verify(
@@ -267,8 +266,6 @@
     public void testSetInternalRestoreState_waitingForStaging_schedulesStagingTimeoutJob() {
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_WAITING_FOR_STAGING));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_STAGING_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         // forcing the state because we want to this state to set even when it's already set.
         mBackupRestore.setInternalRestoreState(INTERNAL_RESTORE_STATE_WAITING_FOR_STAGING, true);
@@ -289,8 +286,6 @@
     public void testSetInternalRestoreState_stagingInProgress_schedulesStagingTimeoutJob() {
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_STAGING_IN_PROGRESS));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_STAGING_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         // forcing the state because we want to this state to set even when it's already set.
         mBackupRestore.setInternalRestoreState(INTERNAL_RESTORE_STATE_STAGING_IN_PROGRESS, true);
@@ -312,8 +307,6 @@
     public void testSetInternalRestoreState_mergingInProgress_schedulesMergingTimeoutJob() {
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_MERGING_IN_PROGRESS));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_STAGING_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         // forcing the state because we want to this state to set even when it's already set.
         mBackupRestore.setInternalRestoreState(INTERNAL_RESTORE_STATE_MERGING_IN_PROGRESS, true);
@@ -335,8 +328,6 @@
         @HealthConnectManager.DataDownloadState int testDownloadStateSet = DATA_DOWNLOAD_STARTED;
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_DOWNLOAD_STATE_KEY, String.valueOf(testDownloadStateSet));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_DOWNLOAD_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         mBackupRestore.scheduleAllJobs();
         ExtendedMockito.verify(
@@ -355,8 +346,6 @@
         @HealthConnectManager.DataDownloadState int testDownloadStateSet = DATA_DOWNLOAD_RETRY;
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_DOWNLOAD_STATE_KEY, String.valueOf(testDownloadStateSet));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_DOWNLOAD_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         mBackupRestore.scheduleAllJobs();
         ExtendedMockito.verify(
@@ -371,11 +360,55 @@
     }
 
     @Test
+    public void testDownloadTimeoutJob_downloadLatencyNotElapsed_usesDefaultLatency() {
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_DOWNLOAD_STATE_KEY, String.valueOf(DATA_DOWNLOAD_STARTED));
+
+        mBackupRestore.scheduleAllJobs();
+        ExtendedMockito.verify(
+                () ->
+                        BackupRestore.BackupRestoreJobService.schedule(
+                                eq(mServiceContext),
+                                mJobInfoArgumentCaptor.capture(),
+                                eq(mBackupRestore)));
+        JobInfo jobInfo = mJobInfoArgumentCaptor.getValue();
+
+        assertThat(jobInfo.getMinLatencyMillis()).isEqualTo(DATA_DOWNLOAD_TIMEOUT_INTERVAL_MILLIS);
+        assertThat(jobInfo.getMaxExecutionDelayMillis())
+                .isEqualTo(DATA_DOWNLOAD_TIMEOUT_INTERVAL_MILLIS + MINIMUM_LATENCY_WINDOW_MILLIS);
+        assertThat(jobInfo.getExtras().getString(EXTRA_JOB_NAME_KEY))
+                .isEqualTo(DATA_DOWNLOAD_TIMEOUT_KEY);
+    }
+
+    @Test
+    public void testDownloadTimeoutJob_downloadLatencyElapsed_usesMinimumLatency() {
+        Instant now = Instant.now();
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_DOWNLOAD_STATE_KEY, String.valueOf(DATA_DOWNLOAD_STARTED));
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_DOWNLOAD_TIMEOUT_KEY,
+                String.valueOf(
+                        now.minusMillis(DATA_DOWNLOAD_TIMEOUT_INTERVAL_MILLIS).toEpochMilli()));
+
+        mBackupRestore.scheduleAllJobs();
+        ExtendedMockito.verify(
+                () ->
+                        BackupRestore.BackupRestoreJobService.schedule(
+                                eq(mServiceContext),
+                                mJobInfoArgumentCaptor.capture(),
+                                eq(mBackupRestore)));
+        JobInfo jobInfo = mJobInfoArgumentCaptor.getValue();
+
+        assertThat(jobInfo.getMinLatencyMillis()).isEqualTo(0);
+        assertThat(jobInfo.getMaxExecutionDelayMillis()).isEqualTo(MINIMUM_LATENCY_WINDOW_MILLIS);
+        assertThat(jobInfo.getExtras().getString(EXTRA_JOB_NAME_KEY))
+                .isEqualTo(DATA_DOWNLOAD_TIMEOUT_KEY);
+    }
+
+    @Test
     public void testScheduleAllPendingJobs_waitingForStaging_schedulesStagingTimeoutJob() {
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_WAITING_FOR_STAGING));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_STAGING_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         mBackupRestore.scheduleAllJobs();
         ExtendedMockito.verify(
@@ -393,8 +426,6 @@
     public void testScheduleAllPendingJobs_stagingInProgress_schedulesStagingTimeoutJob() {
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_STAGING_IN_PROGRESS));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_STAGING_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         mBackupRestore.scheduleAllJobs();
         ExtendedMockito.verify(
@@ -409,11 +440,55 @@
     }
 
     @Test
+    public void testStagingTimeoutJob_stagingLatencyNotElapsed_usesStagingLatency() {
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_WAITING_FOR_STAGING));
+
+        mBackupRestore.scheduleAllJobs();
+        ExtendedMockito.verify(
+                () ->
+                        BackupRestore.BackupRestoreJobService.schedule(
+                                eq(mServiceContext),
+                                mJobInfoArgumentCaptor.capture(),
+                                eq(mBackupRestore)));
+        JobInfo jobInfo = mJobInfoArgumentCaptor.getValue();
+
+        assertThat(jobInfo.getMinLatencyMillis()).isEqualTo(DATA_STAGING_TIMEOUT_INTERVAL_MILLIS);
+        assertThat(jobInfo.getMaxExecutionDelayMillis())
+                .isEqualTo(DATA_STAGING_TIMEOUT_INTERVAL_MILLIS + MINIMUM_LATENCY_WINDOW_MILLIS);
+        assertThat(jobInfo.getExtras().getString(EXTRA_JOB_NAME_KEY))
+                .isEqualTo(DATA_STAGING_TIMEOUT_KEY);
+    }
+
+    @Test
+    public void testStagingTimeoutJob_stagingLatencyElapsed_usesMinimumLatency() {
+        Instant now = Instant.now();
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_WAITING_FOR_STAGING));
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_STAGING_TIMEOUT_KEY,
+                String.valueOf(
+                        now.minusMillis(DATA_STAGING_TIMEOUT_INTERVAL_MILLIS).toEpochMilli()));
+
+        mBackupRestore.scheduleAllJobs();
+        ExtendedMockito.verify(
+                () ->
+                        BackupRestore.BackupRestoreJobService.schedule(
+                                eq(mServiceContext),
+                                mJobInfoArgumentCaptor.capture(),
+                                eq(mBackupRestore)));
+        JobInfo jobInfo = mJobInfoArgumentCaptor.getValue();
+
+        assertThat(jobInfo.getMinLatencyMillis()).isEqualTo(0);
+        assertThat(jobInfo.getMaxExecutionDelayMillis()).isEqualTo(MINIMUM_LATENCY_WINDOW_MILLIS);
+        assertThat(jobInfo.getExtras().getString(EXTRA_JOB_NAME_KEY))
+                .isEqualTo(DATA_STAGING_TIMEOUT_KEY);
+    }
+
+    @Test
     public void testScheduleAllPendingJobs_mergingInProgress_schedulesMergingTimeoutJob() {
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_MERGING_IN_PROGRESS));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_STAGING_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         mBackupRestore.scheduleAllJobs();
         ExtendedMockito.verify(
@@ -431,8 +506,6 @@
     public void testScheduleAllTimeoutJobs_stagingDone_triggersMergingJob() throws Exception {
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_STAGING_DONE));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_STAGING_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         when(mTransactionManager.getDatabaseVersion()).thenReturn(1);
 
@@ -447,11 +520,55 @@
     }
 
     @Test
+    public void testMergingTimeoutJob_mergingLatencyElapsed_usesMergingLatency() {
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_MERGING_IN_PROGRESS));
+
+        mBackupRestore.scheduleAllJobs();
+        ExtendedMockito.verify(
+                () ->
+                        BackupRestore.BackupRestoreJobService.schedule(
+                                eq(mServiceContext),
+                                mJobInfoArgumentCaptor.capture(),
+                                eq(mBackupRestore)));
+        JobInfo jobInfo = mJobInfoArgumentCaptor.getValue();
+
+        assertThat(jobInfo.getMinLatencyMillis()).isEqualTo(DATA_MERGING_TIMEOUT_INTERVAL_MILLIS);
+        assertThat(jobInfo.getMaxExecutionDelayMillis())
+                .isEqualTo(DATA_MERGING_TIMEOUT_INTERVAL_MILLIS + MINIMUM_LATENCY_WINDOW_MILLIS);
+        assertThat(jobInfo.getExtras().getString(EXTRA_JOB_NAME_KEY))
+                .isEqualTo(DATA_MERGING_TIMEOUT_KEY);
+    }
+
+    @Test
+    public void testMergingTimeoutJob_mergingLatencyElapsed_usesMinimumLatency() {
+        Instant now = Instant.now();
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_MERGING_IN_PROGRESS));
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_MERGING_TIMEOUT_KEY,
+                String.valueOf(
+                        now.minusMillis(DATA_MERGING_TIMEOUT_INTERVAL_MILLIS).toEpochMilli()));
+
+        mBackupRestore.scheduleAllJobs();
+        ExtendedMockito.verify(
+                () ->
+                        BackupRestore.BackupRestoreJobService.schedule(
+                                eq(mServiceContext),
+                                mJobInfoArgumentCaptor.capture(),
+                                eq(mBackupRestore)));
+        JobInfo jobInfo = mJobInfoArgumentCaptor.getValue();
+
+        assertThat(jobInfo.getMinLatencyMillis()).isEqualTo(0);
+        assertThat(jobInfo.getMaxExecutionDelayMillis()).isEqualTo(MINIMUM_LATENCY_WINDOW_MILLIS);
+        assertThat(jobInfo.getExtras().getString(EXTRA_JOB_NAME_KEY))
+                .isEqualTo(DATA_MERGING_TIMEOUT_KEY);
+    }
+
+    @Test
     public void testScheduleAllTimeoutJobs_stagingDoneAndMigration_schedulesRetryMergingJob() {
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_STAGING_DONE));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_STAGING_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         when(mMigrationStateManager.isMigrationInProgress()).thenReturn(true);
 
@@ -473,8 +590,6 @@
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_RESTORE_STATE_KEY,
                 String.valueOf(INTERNAL_RESTORE_STATE_MERGING_DONE_OLD_CODE));
-        mFakePreferenceHelper.insertOrReplacePreference(
-                DATA_STAGING_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
 
         when(mMigrationStateManager.isMigrationInProgress()).thenReturn(true);
 
@@ -492,6 +607,58 @@
     }
 
     @Test
+    public void testRetryMergingTimeoutJob_retryLatencyElapsed_usesRetryLatency() {
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_STAGING_DONE));
+
+        when(mMigrationStateManager.isMigrationInProgress()).thenReturn(true);
+
+        mBackupRestore.scheduleAllJobs();
+        ExtendedMockito.verify(
+                () ->
+                        BackupRestore.BackupRestoreJobService.schedule(
+                                eq(mServiceContext),
+                                mJobInfoArgumentCaptor.capture(),
+                                eq(mBackupRestore)),
+                timeout(2000));
+        JobInfo jobInfo = mJobInfoArgumentCaptor.getValue();
+
+        assertThat(jobInfo.getMinLatencyMillis()).isEqualTo(DATA_MERGING_RETRY_DELAY_MILLIS);
+        assertThat(jobInfo.getMaxExecutionDelayMillis())
+                .isEqualTo(DATA_MERGING_RETRY_DELAY_MILLIS + MINIMUM_LATENCY_WINDOW_MILLIS);
+        assertThat(jobInfo.getExtras().getString(EXTRA_JOB_NAME_KEY))
+                .isEqualTo(DATA_MERGING_RETRY_KEY);
+    }
+
+    @Test
+    public void testRetryMergingTimeoutJob_retryLatencyElapsed_usesMinimumLatency() {
+        Instant now = Instant.now();
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_STAGING_DONE));
+        mFakePreferenceHelper.insertOrReplacePreference(
+                DATA_MERGING_RETRY_KEY,
+                String.valueOf(
+                        now.minusMillis(DATA_MERGING_TIMEOUT_INTERVAL_MILLIS).toEpochMilli()));
+
+        when(mMigrationStateManager.isMigrationInProgress()).thenReturn(true);
+
+        mBackupRestore.scheduleAllJobs();
+        ExtendedMockito.verify(
+                () ->
+                        BackupRestore.BackupRestoreJobService.schedule(
+                                eq(mServiceContext),
+                                mJobInfoArgumentCaptor.capture(),
+                                eq(mBackupRestore)),
+                timeout(2000));
+        JobInfo jobInfo = mJobInfoArgumentCaptor.getValue();
+
+        assertThat(jobInfo.getMinLatencyMillis()).isEqualTo(0);
+        assertThat(jobInfo.getMaxExecutionDelayMillis()).isEqualTo(MINIMUM_LATENCY_WINDOW_MILLIS);
+        assertThat(jobInfo.getExtras().getString(EXTRA_JOB_NAME_KEY))
+                .isEqualTo(DATA_MERGING_RETRY_KEY);
+    }
+
+    @Test
     public void testCancelAllJobs_cancelsAllJobs() {
         mBackupRestore.cancelAllJobs();
         ExtendedMockito.verify(
@@ -543,7 +710,7 @@
 
     @Test
     public void testOnStartJob_forWaitingStagingJob_executesStagingJob() {
-       mFakePreferenceHelper.insertOrReplacePreference(
+        mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_RESTORE_STATE_KEY, String.valueOf(INTERNAL_RESTORE_STATE_WAITING_FOR_STAGING));
         mFakePreferenceHelper.insertOrReplacePreference(
                 DATA_STAGING_TIMEOUT_KEY, String.valueOf(Instant.now().toEpochMilli()));
diff --git a/tests/unittests/src/com/android/server/healthconnect/storage/TransactionManagerExerciseRoutesTest.java b/tests/unittests/src/com/android/server/healthconnect/storage/TransactionManagerExerciseRoutesTest.java
index f17187b..a5bcf4d 100644
--- a/tests/unittests/src/com/android/server/healthconnect/storage/TransactionManagerExerciseRoutesTest.java
+++ b/tests/unittests/src/com/android/server/healthconnect/storage/TransactionManagerExerciseRoutesTest.java
@@ -50,6 +50,7 @@
 import java.time.Instant;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -60,7 +61,7 @@
     private static final String FOO_PACKAGE_NAME = "package.foo";
     private static final String BAR_PACKAGE_NAME = "package.bar";
     private static final String UNKNOWN_PACKAGE_NAME = "package.unknown";
-    private static final Map<String, Boolean> NO_EXTRA_PERMS = Map.of();
+    private static final Set<String> NO_EXTRA_PERMS = Set.of();
     @Rule public final HealthConnectDatabaseTestRule testRule = new HealthConnectDatabaseTestRule();
 
     private TransactionTestUtils mTransactionTestUtils;
@@ -103,8 +104,9 @@
                         TEST_PACKAGE_NAME,
                         ImmutableMap.of(
                                 RecordTypeIdentifier.RECORD_TYPE_EXERCISE_SESSION, allUuids),
-                        /* startDateAccess= */ 0,
-                        NO_EXTRA_PERMS);
+                        /* startDateAccessMillis= */ 0,
+                        NO_EXTRA_PERMS,
+                        /* isInForeground= */ true);
 
         List<RecordInternal<?>> returnedRecords = mTransactionManager.readRecordsByIds(request);
 
@@ -134,8 +136,9 @@
                         UNKNOWN_PACKAGE_NAME,
                         ImmutableMap.of(
                                 RecordTypeIdentifier.RECORD_TYPE_EXERCISE_SESSION, List.of(uuid)),
-                        /* startDateAccess= */ 0,
-                        NO_EXTRA_PERMS);
+                        /* startDateAccessMillis= */ 0,
+                        NO_EXTRA_PERMS,
+                        /* isInForeground= */ true);
 
         List<RecordInternal<?>> returnedRecords = mTransactionManager.readRecordsByIds(request);
 
@@ -158,8 +161,9 @@
                         null,
                         ImmutableMap.of(
                                 RecordTypeIdentifier.RECORD_TYPE_EXERCISE_SESSION, List.of(uuid)),
-                        /* startDateAccess= */ 0,
-                        NO_EXTRA_PERMS);
+                        /* startDateAccessMillis= */ 0,
+                        NO_EXTRA_PERMS,
+                        /* isInForeground= */ true);
 
         List<RecordInternal<?>> returnedRecords = mTransactionManager.readRecordsByIds(request);
 
@@ -182,8 +186,9 @@
                         UNKNOWN_PACKAGE_NAME,
                         ImmutableMap.of(
                                 RecordTypeIdentifier.RECORD_TYPE_EXERCISE_SESSION, List.of(uuid)),
-                        /* startDateAccess= */ 0,
-                        Map.of(HealthPermissions.READ_EXERCISE_ROUTE, true));
+                        /* startDateAccessMillis= */ 0,
+                        Set.of(HealthPermissions.READ_EXERCISE_ROUTE),
+                        /* isInForeground= */ true);
 
         List<RecordInternal<?>> returnedRecords = mTransactionManager.readRecordsByIds(request);
 
@@ -218,7 +223,8 @@
                                 .toReadRecordsRequestParcel(),
                         /* startDateAccessMillis= */ 0,
                         /* enforceSelfRead= */ false,
-                        NO_EXTRA_PERMS);
+                        NO_EXTRA_PERMS,
+                        /* isInForeground= */ true);
 
         List<RecordInternal<?>> returnedRecords =
                 mTransactionManager.readRecordsAndPageToken(request).first;
@@ -256,7 +262,8 @@
                                 .toReadRecordsRequestParcel(),
                         /* startDateAccessMillis= */ 0,
                         /* enforceSelfRead= */ false,
-                        NO_EXTRA_PERMS);
+                        NO_EXTRA_PERMS,
+                        /* isInForeground= */ true);
 
         List<RecordInternal<?>> returnedRecords =
                 mTransactionManager.readRecordsAndPageToken(request).first;
@@ -286,7 +293,8 @@
                                 .toReadRecordsRequestParcel(),
                         /* startDateAccessMillis= */ 0,
                         /* enforceSelfRead= */ false,
-                        NO_EXTRA_PERMS);
+                        NO_EXTRA_PERMS,
+                        /* isInForeground= */ true);
 
         List<RecordInternal<?>> returnedRecords =
                 mTransactionManager.readRecordsAndPageToken(request).first;
@@ -316,7 +324,8 @@
                                 .toReadRecordsRequestParcel(),
                         /* startDateAccessMillis= */ 0,
                         /* enforceSelfRead= */ false,
-                        Map.of(HealthPermissions.READ_EXERCISE_ROUTE, true));
+                        Set.of(HealthPermissions.READ_EXERCISE_ROUTE),
+                        /* isInForeground= */ true);
 
         List<RecordInternal<?>> returnedRecords =
                 mTransactionManager.readRecordsAndPageToken(request).first;
diff --git a/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/RecordHelperTest.java b/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/RecordHelperTest.java
index f8b1112..a60554b 100644
--- a/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/RecordHelperTest.java
+++ b/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/RecordHelperTest.java
@@ -54,6 +54,7 @@
 import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 import java.util.UUID;
 
 @RunWith(AndroidJUnit4.class)
@@ -306,6 +307,7 @@
                 TEST_PACKAGE_NAME,
                 /* enforceSelfRead= */ false,
                 /* startDateAccess= */ 0,
-                /* extraPermsState= */ null);
+                /* grantedExtraReadPermissions= */ Set.of(),
+                /* isInForeground= */ true);
     }
 }
diff --git a/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/TransactionTestUtils.java b/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/TransactionTestUtils.java
index b1bf925..d2b6088 100644
--- a/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/TransactionTestUtils.java
+++ b/tests/unittests/src/com/android/server/healthconnect/storage/datatypehelpers/TransactionTestUtils.java
@@ -45,12 +45,13 @@
 import java.time.Instant;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.UUID;
 import java.util.stream.IntStream;
 
 /** Util class provides shared functionality for db transaction testing. */
 public final class TransactionTestUtils {
-    private static final Map<String, Boolean> NO_EXTRA_PERMS = Map.of();
+    private static final Set<String> NO_EXTRA_PERMS = Set.of();
     private static final String TEST_PACKAGE_NAME = "package.name";
     private final TransactionManager mTransactionManager;
     private final Context mContext;
@@ -90,7 +91,11 @@
     public static ReadTransactionRequest getReadTransactionRequest(
             Map<Integer, List<UUID>> recordTypeToUuids) {
         return new ReadTransactionRequest(
-                TEST_PACKAGE_NAME, recordTypeToUuids, /* startDateAccess= */ 0, NO_EXTRA_PERMS);
+                TEST_PACKAGE_NAME,
+                recordTypeToUuids,
+                /* startDateAccessMillis= */ 0,
+                NO_EXTRA_PERMS,
+                /* isInForeground= */ true);
     }
 
     public static ReadTransactionRequest getReadTransactionRequest(
@@ -100,7 +105,8 @@
                 request,
                 /* startDateAccessMillis= */ 0,
                 /* enforceSelfRead= */ false,
-                NO_EXTRA_PERMS);
+                NO_EXTRA_PERMS,
+                /* isInForeground= */ true);
     }
 
     public static RecordInternal<StepsRecord> createStepsRecord(