Skip to content

Commit be15d52

Browse files
committed
Fix #516
1 parent 93a26db commit be15d52

16 files changed

Lines changed: 121 additions & 51 deletions

File tree

apps/carp_mobile_sensing_app/android/app/build.gradle

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ android {
1212

1313
compileOptions {
1414
coreLibraryDesugaringEnabled = true
15-
sourceCompatibility = JavaVersion.VERSION_1_8
16-
targetCompatibility = JavaVersion.VERSION_1_8
15+
sourceCompatibility = JavaVersion.VERSION_17
16+
targetCompatibility = JavaVersion.VERSION_17
1717
}
1818

1919
kotlinOptions {
20-
jvmTarget = JavaVersion.VERSION_1_8
20+
jvmTarget = '17'
2121
}
2222

2323
defaultConfig {
@@ -44,6 +44,8 @@ dependencies {
4444
// Use to implement Health Connect. Requires SDK level 34.
4545
implementation "androidx.health.connect:connect-client:1.1.0-rc02"
4646
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
47+
// AppCompat library for Theme.AppCompat.NoActionBar
48+
implementation 'androidx.appcompat:appcompat:1.7.0'
4749
}
4850

4951
flutter {

apps/carp_mobile_sensing_app/android/app/src/main/AndroidManifest.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
2828
<uses-permission android:name="android.permission.WAKE_LOCK" />
2929
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
30+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
3031
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
3132

3233
<!-- for Android 9 (API 28 and below), use: -->
@@ -194,5 +195,13 @@
194195
<meta-data
195196
android:name="flutterEmbedding"
196197
android:value="2" />
198+
199+
<!-- Location service with foreground service type for Android 14+ -->
200+
<service
201+
android:name="com.lyokone.location.FlutterLocationService"
202+
android:enabled="true"
203+
android:exported="false"
204+
android:foregroundServiceType="location"
205+
tools:replace="android:foregroundServiceType" />
197206
</application>
198207
</manifest>

apps/carp_mobile_sensing_app/android/settings.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ plugins {
2323
// id "org.jetbrains.kotlin.android" version "2.0.0" apply false
2424

2525
id "com.android.application" version '8.10.1' apply false
26-
id "org.jetbrains.kotlin.android" version "1.8.22" apply false
26+
id "org.jetbrains.kotlin.android" version "2.1.0" apply false
2727
}
2828

2929
include ":app"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
description: This file stores settings for Dart & Flutter DevTools.
2+
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
3+
extensions:

apps/carp_mobile_sensing_app/lib/main.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import 'package:carp_cortrium_package/carp_cortrium_package.dart';
2525
import 'package:carp_webservices/carp_auth/carp_auth.dart';
2626
import 'package:carp_webservices/carp_services/carp_services.dart';
2727
import 'package:carp_backend/carp_backend.dart';
28+
import 'package:package_info_plus/package_info_plus.dart';
2829

2930
import 'config.dart';
3031

apps/carp_mobile_sensing_app/lib/src/app.dart

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,24 @@ class LoadingPage extends StatelessWidget {
2020
///
2121
/// Returns true when successfully done.
2222
Future<bool> init(BuildContext context) async {
23-
// Try to get location permissions as the first thing.
23+
print('LoadingPage.init() - Starting initialization...');
24+
25+
// Request all necessary permissions upfront
26+
print('LoadingPage.init() - Requesting permissions...');
2427
await Permission.locationWhenInUse.request();
28+
await Permission.locationAlways.request();
29+
await Permission.activityRecognition.request();
30+
await Permission.sensors.request();
31+
32+
// For Android 14+, also request notification permission for foreground services
33+
if (Theme.of(context).platform == TargetPlatform.android) {
34+
await Permission.notification.request();
35+
}
36+
print('LoadingPage.init() - Permissions requested.');
2537

2638
// Initialize and use the CAWS backend if not in local deployment mode
2739
if (bloc.deploymentMode != DeploymentMode.local) {
40+
print('LoadingPage.init() - Initializing CAWS backend...');
2841
await CarpBackend().initialize();
2942
await CarpBackend().authenticate();
3043

@@ -39,8 +52,11 @@ class LoadingPage extends StatelessWidget {
3952
CarpService().study = bloc.study;
4053
}
4154

55+
print('LoadingPage.init() - Initializing sensing...');
4256
await bloc.sensing.initialize();
57+
print('LoadingPage.init() - Sensing initialized.');
4358

59+
print('LoadingPage.init() - Initialization complete!');
4460
return true;
4561
}
4662

apps/carp_mobile_sensing_app/lib/src/blocs/local_study_protocol_manager.dart

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,15 @@ class LocalStudyProtocolManager implements StudyProtocolManager {
118118
// locationService);
119119

120120
// Define the online weather service and add it as a 'device'
121-
WeatherService weatherService = WeatherService(apiKey: openWeatherApiKey);
122-
protocol.addConnectedDevice(weatherService, phone);
121+
// WeatherService weatherService = WeatherService(apiKey: openWeatherApiKey);
122+
// protocol.addConnectedDevice(weatherService, phone);
123123

124-
// Add a background task that collects weather every 5 minutes.
125-
protocol.addTaskControl(
126-
PeriodicTrigger(period: Duration(minutes: 5)),
127-
BackgroundTask(
128-
measures: [Measure(type: ContextSamplingPackage.WEATHER)]),
129-
weatherService);
124+
// // Add a background task that collects weather every 5 minutes.
125+
// protocol.addTaskControl(
126+
// PeriodicTrigger(period: Duration(minutes: 5)),
127+
// BackgroundTask(
128+
// measures: [Measure(type: ContextSamplingPackage.WEATHER)]),
129+
// weatherService);
130130

131131
// // Define the online air quality service and add it as a 'device'
132132
// AirQualityService airQualityService =
@@ -317,7 +317,7 @@ class LocalStudyProtocolManager implements StudyProtocolManager {
317317

318318
var c3 = CortriumDevice(
319319
name: 'Cortrium C3+',
320-
identifier: 'ED:AD:D4:3D:3F:72',
320+
btleAddress: 'ED:AD:D4:3D:3F:72',
321321
);
322322

323323
protocol.addConnectedDevice(c3, phone);
@@ -329,6 +329,7 @@ class LocalStudyProtocolManager implements StudyProtocolManager {
329329
// Measure(type: CortriumSamplingPackage.BUTTON),
330330
Measure(type: CortriumSamplingPackage.BATTERY),
331331
Measure(type: CortriumSamplingPackage.ACCELEROMETER),
332+
Measure(type: CortriumSamplingPackage.HR),
332333
]),
333334
c3);
334335

@@ -460,28 +461,28 @@ class LocalStudyProtocolManager implements StudyProtocolManager {
460461
locationService);
461462

462463
// define the online weather service and add it to the father's phone
463-
WeatherService weatherService = WeatherService(apiKey: openWeatherApiKey);
464-
protocol.addConnectedDevice(weatherService, fatherPhone);
464+
// WeatherService weatherService = WeatherService(apiKey: openWeatherApiKey);
465+
// protocol.addConnectedDevice(weatherService, fatherPhone);
465466

466-
// add a background task that collects weather every 30 minutes.
467-
protocol.addTaskControl(
468-
PeriodicTrigger(period: Duration(minutes: 30)),
469-
BackgroundTask()
470-
..addMeasure(Measure(type: ContextSamplingPackage.WEATHER)),
471-
weatherService);
467+
// // add a background task that collects weather every 30 minutes.
468+
// protocol.addTaskControl(
469+
// PeriodicTrigger(period: Duration(minutes: 30)),
470+
// BackgroundTask()
471+
// ..addMeasure(Measure(type: ContextSamplingPackage.WEATHER)),
472+
// weatherService);
472473

473-
// define the online air quality service and add it to the mother's phone
474-
AirQualityService airQualityService =
475-
AirQualityService(apiKey: airQualityApiKey);
476-
protocol.addConnectedDevice(airQualityService, motherPhone);
474+
// // define the online air quality service and add it to the mother's phone
475+
// AirQualityService airQualityService =
476+
// AirQualityService(apiKey: airQualityApiKey);
477+
// protocol.addConnectedDevice(airQualityService, motherPhone);
477478

478-
// add a background task that air quality every 30 minutes.
479-
protocol.addTaskControl(
480-
PeriodicTrigger(period: Duration(minutes: 30)),
481-
BackgroundTask(measures: [
482-
Measure(type: ContextSamplingPackage.AIR_QUALITY),
483-
]),
484-
airQualityService);
479+
// // add a background task that air quality every 30 minutes.
480+
// protocol.addTaskControl(
481+
// PeriodicTrigger(period: Duration(minutes: 30)),
482+
// BackgroundTask(measures: [
483+
// Measure(type: ContextSamplingPackage.AIR_QUALITY),
484+
// ]),
485+
// airQualityService);
485486

486487
// collect noise from the child's phone
487488
protocol.addTaskControl(

apps/carp_mobile_sensing_app/lib/src/blocs/sensing.dart

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,24 +89,29 @@ class Sensing {
8989
/// Initialize and set up sensing.
9090
Future<void> initialize() async {
9191
info('Initializing $runtimeType - mode: ${bloc.deploymentMode}');
92+
print('Sensing.initialize() - Step 1: Starting...');
9293

9394
switch (bloc.deploymentMode) {
9495
case DeploymentMode.local:
96+
print('Sensing.initialize() - Step 2: Creating local deployment service...');
9597
// Use the local, phone-based deployment service.
9698
deploymentService = SmartphoneDeploymentService();
9799

98100
// Get the protocol from the local study protocol manager.
99101
// Note that the study id is not used.
102+
print('Sensing.initialize() - Step 3: Getting study protocol...');
100103
StudyProtocol protocol =
101104
await LocalStudyProtocolManager().getStudyProtocol('');
102105

103106
// Deploy this protocol using the on-phone deployment service.
104107
// Reuse the study deployment id, if this is stored on the phone.
108+
print('Sensing.initialize() - Step 4: Creating study deployment...');
105109
_status = await SmartphoneDeploymentService().createStudyDeployment(
106110
protocol,
107111
);
108112

109113
// Save the study on the phone for later use.
114+
print('Sensing.initialize() - Step 5: Saving study...');
110115
bloc.study = SmartphoneStudy(
111116
studyDeploymentId: _status!.studyDeploymentId,
112117
deviceRoleName: _status!.primaryDeviceStatus!.device.roleName,
@@ -125,20 +130,39 @@ class Sensing {
125130

126131
// Configure the client manager with the deployment service selected above
127132
// (local or CAWS), add the study, and deploy it.
133+
print('Sensing.initialize() - Step 6: Configuring client manager...');
128134
await SmartPhoneClientManager().configure(
129135
deploymentService: deploymentService,
130-
askForPermissions: true,
136+
askForPermissions: true, // Allow the system to request permissions as needed
131137
);
132138

139+
print('Sensing.initialize() - Step 7: Adding study...');
133140
study = await SmartPhoneClientManager().addStudy(bloc.study!);
141+
142+
print('Sensing.initialize() - Step 8: Trying deployment...');
134143
await controller?.tryDeployment(useCached: bloc.useCachedStudyDeployment);
135-
await controller?.configure();
144+
145+
print('Sensing.initialize() - Step 9: Configuring controller...');
146+
try {
147+
await controller?.configure().timeout(
148+
Duration(seconds: 30),
149+
onTimeout: () {
150+
print('Sensing.initialize() - WARNING: Configure timed out after 30 seconds');
151+
print('Sensing.initialize() - Continuing anyway...');
152+
},
153+
);
154+
} catch (error) {
155+
print('Sensing.initialize() - ERROR during configure: $error');
156+
print('Sensing.initialize() - Continuing anyway...');
157+
}
136158

137159
// Listen on the measurements stream and print them as json.
160+
print('Sensing.initialize() - Step 10: Setting up measurement listener...');
138161
SmartPhoneClientManager()
139162
.measurements
140163
.listen((measurement) => print(toJsonString(measurement)));
141164

142165
info('$runtimeType initialized');
166+
print('Sensing.initialize() - Complete!');
143167
}
144168
}

apps/carp_mobile_sensing_app/pubspec.yaml

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,17 @@ platforms:
1313
ios:
1414

1515
dependencies:
16+
battery_plus: ^6.2.3
17+
device_calendar: ^4.3.1
18+
device_info_plus: ^12.1.0
1619
flutter:
1720
sdk: flutter
1821
flutter_launcher_icons: ^0.14.0
19-
permission_handler: ^11.0.0
22+
flutter_local_notifications: ^19.4.2
23+
location: ^8.0.1
24+
mdsflutter: ^2.3.1
25+
package_info_plus: ^8.3.1
26+
permission_handler: '>=11.0.0 <13.0.0'
2027

2128
#carp_serializable: ^1.1.0
2229
#carp_core: ^0.30.0
@@ -35,7 +42,10 @@ dependencies:
3542
# carp_movisens_package: ^0.32.0
3643

3744
research_package: ^2.0.0
38-
# health: ^8.1.0
45+
shared_preferences: ^2.5.3
46+
sqflite: ^2.4.2
47+
health: ^13.2.0
48+
flutter_blue_plus: ^1.36.8
3949

4050
# Overriding carp libraries to use the local copy
4151
dependency_overrides:
@@ -89,14 +99,18 @@ dependency_overrides:
8999
git: https://github.com/bardram/device_calendar
90100

91101
# due to this issue https://github.com/petri-lipponen-movesense/mdsflutter/issues/36
92-
mdsflutter:
93-
git:
94-
url: https://github.com/Panosfunk/mdsflutter.git
95-
ref: master
102+
# mdsflutter:
103+
# git:
104+
# url: https://github.com/Panosfunk/mdsflutter.git
105+
# ref: master
96106

97107
# due to this issue https://github.com/cph-cachet/carp_studies_app/issues/427
98-
polar: 7.5.1
99-
108+
# polar: 7.7.0
109+
# load polar from https://github.com/iarata/polar
110+
polar:
111+
git:
112+
url: https://github.com/iarata/polar.git
113+
ref: master
100114

101115
dev_dependencies:
102116
flutter_test:

backends/carp_backend/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ dev_dependencies:
5252
json_serializable: any
5353
test: any
5454
flutter_lints: any
55-
shared_preferences: ^2.2.3
55+
shared_preferences: ^2.5.3
5656

5757
flutter:
5858
uses-material-design: true # need this since both RP and carp_webservices uses MD

0 commit comments

Comments
 (0)