-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstudy_protocol_manager.dart
274 lines (247 loc) · 10.9 KB
/
study_protocol_manager.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*
* Copyright 2021-2023 Copenhagen Center for Health Technology (CACHET) at the
* Technical University of Denmark (DTU).
* Use of this source code is governed by a MIT-style license that can be
* found in the LICENSE file.
*/
part of pulmonary_monitor_app;
/// This is a simple local [StudyProtocolManager] which
/// creates the Pulmonary Monitor study protocol.
class LocalStudyProtocolManager implements StudyProtocolManager {
@override
Future<void> initialize() async {}
@override
Future<SmartphoneStudyProtocol> getStudyProtocol(String studyId) async {
SmartphoneStudyProtocol protocol = SmartphoneStudyProtocol(
name: 'Pulmonary Monitor',
ownerId: '[email protected]',
);
protocol.studyDescription = StudyDescription(
title: 'Pulmonary Monitor',
description:
"With the Pulmonary Monitor you can monitor your respiratory health. "
"By using the phones sensors, including the microphone, it will try to monitor you breathing, heart rate, sleep, social contact to others, and your movement. "
"You will also be able to fill in a simple daily survey to help us understand how you're doing. "
"Before you start, please also fill in the demographics survey. ",
purpose:
'To collect basic data from users in their everyday life in order '
'to investigate pulmonary-related symptoms.',
responsible: StudyResponsible(
id: 'jakba',
title: 'Professor',
address: 'Ørsteds Plads, 2100 Kgs. Lyngby',
affiliation: 'Technical University of Denmark',
email: '[email protected]',
name: 'Jakob E. Bardram',
));
// Define the data end point , i.e., where to store data.
// This example app only stores data locally in a SQLite DB
protocol.dataEndPoint = SQLiteDataEndPoint();
// Define which devices are used for data collection.
Smartphone phone = Smartphone();
protocol.addPrimaryDevice(phone);
// Define the online weather service and add it as a 'device'
WeatherService weatherService =
WeatherService(apiKey: '12b6e28582eb9298577c734a31ba9f4f');
protocol.addConnectedDevice(weatherService, phone);
// Define the online air quality service and add it as a 'device'
AirQualityService airQualityService =
AirQualityService(apiKey: '9e538456b2b85c92647d8b65090e29f957638c77');
protocol.addConnectedDevice(airQualityService, phone);
// // Add the background sensing
// protocol.addTaskControl(
// ImmediateTrigger(),
// BackgroundTask(measures: [
// Measure(type: SensorSamplingPackage.STEP_COUNT),
// Measure(type: SensorSamplingPackage.AMBIENT_LIGHT),
// Measure(type: DeviceSamplingPackage.SCREEN_EVENT),
// Measure(type: DeviceSamplingPackage.FREE_MEMORY),
// Measure(type: DeviceSamplingPackage.BATTERY_STATE),
// ]),
// phone);
// // Add activity measure using the phone
// protocol.addTaskControl(
// ImmediateTrigger(),
// BackgroundTask(
// measures: [Measure(type: ContextSamplingPackage.ACTIVITY)]),
// phone);
// Define the online location service and add it as a 'device'.
LocationService locationService = LocationService(
// used for debugging when the phone is laying still on the table
distance: 0,
);
protocol.addConnectedDevice(locationService, phone);
// // Add a background task that continuously collects location
// // and mobility features (e.g., home stay).
// protocol.addTaskControl(
// ImmediateTrigger(),
// BackgroundTask(measures: [
// Measure(type: ContextSamplingPackage.LOCATION),
// Measure(type: ContextSamplingPackage.MOBILITY)
// ]),
// locationService);
// The following contains the definition of the app (user) tasks.
// // Add an app task that once pr. hour asks the user to
// // collect air quality and weather data - and notify the user.
// //
// // Note that for this to work, the air_quality and weather services needs
// // to be defined and added as connected devices to this phone.
// protocol.addTaskControl(
// PeriodicTrigger(period: const Duration(hours: 1)),
// AppTask(
// type: BackgroundSensingUserTask.ONE_TIME_SENSING_TYPE,
// title: "Weather & Air Quality",
// description: "Collect local weather and air quality data",
// notification: true,
// measures: [
// Measure(type: ContextSamplingPackage.WEATHER),
// Measure(type: ContextSamplingPackage.AIR_QUALITY),
// ]),
// phone);
var symptomsTask = RPAppTask(
type: SurveyUserTask.SURVEY_TYPE,
title: surveys.symptoms.title,
description: surveys.symptoms.description,
minutesToComplete: surveys.symptoms.minutesToComplete,
rpTask: surveys.symptoms.survey,
measures: [Measure(type: ContextSamplingPackage.CURRENT_LOCATION)],
);
var demographicsTask = RPAppTask(
type: SurveyUserTask.SURVEY_TYPE,
title: surveys.demographics.title,
description: surveys.demographics.description,
minutesToComplete: surveys.demographics.minutesToComplete,
notification: true,
rpTask: surveys.demographics.survey,
measures: [Measure(type: ContextSamplingPackage.CURRENT_LOCATION)],
);
// always have a symptoms task on the list
protocol.addTaskControl(
NoUserTaskTrigger(taskName: symptomsTask.name),
symptomsTask,
phone,
);
// when a symptoms task is filled, add the demographics task
protocol.addTaskControl(
UserTaskTrigger(
taskName: symptomsTask.name, triggerCondition: UserTaskState.done),
demographicsTask,
phone);
// // Collect symptoms daily at 13:30
// protocol.addTaskControl(
// RecurrentScheduledTrigger(
// type: RecurrentType.daily,
// time: const TimeOfDay(hour: 13, minute: 30),
// ),
// symptomsTask,
// phone);
// // Perform a cognitive assessment every 2nd hour.
// protocol.addTaskControl(
// PeriodicTrigger(period: const Duration(hours: 2)),
// RPAppTask(
// type: SurveyUserTask.COGNITIVE_ASSESSMENT_TYPE,
// title: surveys.cognition.title,
// description: surveys.cognition.description,
// minutesToComplete: surveys.cognition.minutesToComplete,
// rpTask: surveys.cognition.survey,
// measures: [Measure(type: ContextSamplingPackage.CURRENT_LOCATION)],
// ),
// phone);
// // Collect a coughing sample on a daily basis.
// // Also collect current location, and local weather and air quality of this
// // sample.
// protocol.addTaskControl(
// PeriodicTrigger(period: const Duration(days: 1)),
// AppTask(
// type: AudioUserTask.AUDIO_TYPE,
// title: "Coughing",
// description:
// 'In this small exercise we would like to collect sound samples of coughing.',
// instructions:
// 'Please press the record button below, and then cough 5 times.',
// minutesToComplete: 3,
// notification: true,
// measures: [
// Measure(type: MediaSamplingPackage.AUDIO),
// Measure(type: ContextSamplingPackage.CURRENT_LOCATION),
// Measure(type: ContextSamplingPackage.WEATHER),
// Measure(type: ContextSamplingPackage.AIR_QUALITY),
// ],
// ),
// phone);
// // Add audio measure in the background
// protocol.addTaskControl(
// PeriodicTrigger(period: Duration(seconds: 40)),
// BackgroundTask(
// measures: [Measure(type: MediaSamplingPackage.AUDIO)],
// duration: const Duration(seconds: 5),
// ),
// phone);
// // Perform a Parkinson's assessment.
// // This is strictly speaking not part of monitoring pulmonary symptoms,
// // but is included to illustrate the use of cognitive tests from the
// // cognition package.
// protocol.addTaskControl(
// PeriodicTrigger(period: const Duration(hours: 2)),
// RPAppTask(
// type: SurveyUserTask.COGNITIVE_ASSESSMENT_TYPE,
// title: "Parkinson's' Assessment",
// description: "A simple task assessing finger tapping speed.",
// minutesToComplete: 3,
// rpTask: RPOrderedTask(
// identifier: "parkinsons_assessment",
// steps: [
// RPInstructionStep(
// identifier: 'parkinsons_instruction',
// title: "Parkinsons' Disease Assessment",
// text:
// "In the following pages, you will be asked to solve two simple test which will help assess your symptoms on a daily basis. "
// "Each test has an instruction page, which you should read carefully before starting the test.\n\n"
// "Please sit down comfortably and hold the phone in one hand while performing the test with the other."),
// RPTimerStep(
// identifier: 'RPTimerStepID',
// timeout: const Duration(seconds: 6),
// title:
// "Please stand up and hold the phone in one hand and lift it in a straight arm until you hear the sound.",
// playSound: true,
// ),
// RPFlankerActivity(
// identifier: 'flanker_1',
// lengthOfTest: 30,
// numberOfCards: 10,
// ),
// RPTappingActivity(
// identifier: 'tapping_1',
// lengthOfTest: 10,
// )
// ],
// ),
// measures: [
// Measure(type: SensorSamplingPackage.ACCELERATION),
// Measure(type: SensorSamplingPackage.ROTATION),
// ]),
// phone);
// Add a task that keeps reappearing when done.
var environmentTask = AppTask(
type: BackgroundSensingUserTask.ONE_TIME_SENSING_TYPE,
title: "Location, Weather & Air Quality",
description: "Collect location, weather and air quality",
measures: [
Measure(type: ContextSamplingPackage.CURRENT_LOCATION),
Measure(type: ContextSamplingPackage.WEATHER),
Measure(type: ContextSamplingPackage.AIR_QUALITY),
]);
protocol.addTaskControl(ImmediateTrigger(), environmentTask, phone);
protocol.addTaskControl(
UserTaskTrigger(
taskName: environmentTask.name,
triggerCondition: UserTaskState.done),
environmentTask,
phone);
return protocol;
}
@override
Future<bool> saveStudyProtocol(String studyId, StudyProtocol protocol) async {
throw UnimplementedError();
}
}