Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 1.5.0 #381

Merged
merged 7 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions carp_mobile_sensing/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## 1.5.0

* Improvements to the Notification Controller
* support app-specific methods to create, schedule, and cancel app-specific notifications
* asks for permission on Android (Issue [#375](https://github.com/cph-cachet/carp.sensing-flutter/issues/375))
* tapping a notification takes the user to the right task in the app (Issue [#376](https://github.com/cph-cachet/carp.sensing-flutter/issues/376))
* fix of [#379](https://github.com/cph-cachet/carp.sensing-flutter/issues/379)

## 1.4.7

* improvements to handling connected BLE devices
Expand Down
47 changes: 38 additions & 9 deletions carp_mobile_sensing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,35 +28,64 @@ dependencies:

When you want to add CAMS to you app, there are a few things to do in terms of configuring your app.

First, since CAMS rely on the [flutter_local_notifications](https://pub.dev/packages/flutter_local_notifications) plugin, you should configure your app to the [platforms it supports](https://pub.dev/packages/flutter_local_notifications#-supported-platforms) and configure your app for both [Android](https://pub.dev/packages/flutter_local_notifications#-android-setup) and [iOS](https://pub.dev/packages/flutter_local_notifications#-ios-setup).
First, CAMS rely on the [flutter_local_notifications](https://pub.dev/packages/flutter_local_notifications) plugin. So **if you want to use App Tasks and notifications** you should configure your app to the [platforms it supports](https://pub.dev/packages/flutter_local_notifications#-supported-platforms) and configure your app for both [Android](https://pub.dev/packages/flutter_local_notifications#-android-setup) and [iOS](https://pub.dev/packages/flutter_local_notifications#-ios-setup). There is a lot of details in configuring for notifications - especially for Android - so read this carefully.

### Android Integration

Set the minimum android SDK to 23 and Java SDK Version to 33 by setting the `minSdkVersion`, the `compileSdkVersion`, and `targetSdkVersion` in the `build.gradle` file, located in the `android/app/` folder:
Set the minimum android SDK to 26 and Java SDK Version to 34 by setting the `minSdkVersion`, the `compileSdkVersion`, and `targetSdkVersion` in the `build.gradle` file, located in the `android/app/` folder:

```gradle
android {
compileSdkVersion 33
compileSdkVersion 34

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}

defaultConfig {
minSdkVersion 23
targetSdkVersion 33
...
minSdkVersion 26
targetSdkVersion flutter.targetSdkVersion
...
}
...
}
```

The pedometer (step count) probe needs permission to `ACTIVITY_RECOGNITION`.
Schedule notifications (if using `AppTask`) needs permissions to `SCHEDULE_EXACT_ALARM` and `USE_EXACT_ALARM`. Add the following to your app's `manifest.xml` file located in `android/app/src/main`:
Scheduled notifications (if using `AppTask`) needs a set of permissions, such as `USE_EXACT_ALARM` and `VIBRATE`.
If collecting step counts or using notifications in your app, add the following to your app's `manifest.xml` file located in `android/app/src/main`:

````xml
<!-- Used for activity recognition (step count) -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
android:maxSdkVersion="32" />

<!-- Used for sending and scheduling notifications -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
android:maxSdkVersion="32" />
````

Also specify the following between the `<application>` tags so that the plugin can show the scheduled notifications:

```xml
<!-- Used for scheduling notifications -->
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
```

### iOS Integration

The pedometer (step count) probe uses `NSMotion` on iOS and the `NSMotionUsageDescription` needs to be specified in the app's `Info.plist` file located in `ios/Runner`:
Expand Down Expand Up @@ -205,7 +234,7 @@ Calling `SmartPhoneClientManager().dispose()` would dispose of the client manage

## Extending CAMS

CAMS is designed to be extended in many ways, including [adding new sampling capabilities](https://github.com/cph-cachet/carp.sensing-flutter/wiki/5.-Extending-CARP-Mobile-Sensing#adding-new-sampling-capabilities) by implementing a SamplingPackage, [adding a new data management and backend support](https://github.com/cph-cachet/carp.sensing-flutter/wiki/5.-Extending-CARP-Mobile-Sensing#adding-a-new-data-manager) by creating a DataManager, and [creating data and privacy transformer schemas](https://github.com/cph-cachet/carp.sensing-flutter/wiki/5.-Extending-CARP-Mobile-Sensing#adding-data-and-privacy-transformers) that can transform CARP data to other formats, including privacy protecting them, by implementing a [TransformerSchema](https://pub.dev/documentation/carp_mobile_sensing/latest/domain/DataTransformerSchema-class.html).
CAMS is designed to be extended in many ways, including [adding new sampling capabilities](https://github.com/cph-cachet/carp.sensing-flutter/wiki/5.-Extending-CARP-Mobile-Sensing#adding-new-sampling-capabilities) by implementing a Sampling Package, [adding a new data management and backend support](https://github.com/cph-cachet/carp.sensing-flutter/wiki/5.-Extending-CARP-Mobile-Sensing#adding-a-new-data-manager) by creating a Data Manager, and [creating data and privacy transformer schemas](https://github.com/cph-cachet/carp.sensing-flutter/wiki/5.-Extending-CARP-Mobile-Sensing#adding-data-and-privacy-transformers) that can transform CARP data to other formats, including privacy protecting them, by implementing a [Transformer Schema](https://pub.dev/documentation/carp_mobile_sensing/latest/domain/DataTransformerSchema-class.html).

For example, you can write your own `DataEndPoint` definitions and a corresponding [`DataManager`](https://pub.dev/documentation/carp_mobile_sensing/latest/runtime/DataManager-class.html) class for uploading data to your own data endpoint. See the wiki on how to [add a new data manager](https://github.com/cph-cachet/carp.sensing-flutter/wiki/5.-Extending-CARP-Mobile-Sensing#adding-a-new-data-manager).

Expand Down
2 changes: 1 addition & 1 deletion carp_mobile_sensing/analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ linter:
constant_identifier_names: false
depend_on_referenced_packages: true
avoid_print: false
use_string_in_part_of_directives: false
use_string_in_part_of_directives: true
1 change: 0 additions & 1 deletion carp_mobile_sensing/example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"

android {
// compileSdkVersion flutter.compileSdkVersion
compileSdkVersion 34

compileOptions {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dk.cachet.carp_mobile_sensing_example">

<!-- The following permissions are used in CARP Mobile Sensing -->
<!-- Used for activity recognition (step count) -->
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />

<!-- Used for sending and scheduling notifications -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"
android:maxSdkVersion="32" />

<application
android:label="CAMS Example App"
Expand Down Expand Up @@ -35,5 +43,21 @@
<meta-data
android:name="flutterEmbedding"
android:value="2" />

<!-- Used for scheduling notifications -->
<service
android:name="com.dexterous.flutterlocalnotifications.ForegroundService"
android:exported="false"
android:stopWithTask="false"/>
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver android:exported="false" android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>

</application>
</manifest>
13 changes: 9 additions & 4 deletions carp_mobile_sensing/example/lib/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -358,16 +358,18 @@ void example_3() async {
final client = SmartPhoneClientManager();

// default configuration using:
// * [AwesomeNotificationController]
// * [FlutterLocalNotificationController]
// * [SmartphoneDeploymentService]
// * [DeviceController]
// * asking for permissions
// * notifications enabled
await client.configure();

// use flutter_local_notification for notifications
// disabling notifications, device heartbeat, and permissions handling
await client.configure(
notificationController: FlutterLocalNotificationController(),
askForPermissions: false,
enableNotifications: false,
heartbeat: false,
askForPermissions: false,
);

// add and deploy the protocol
Expand Down Expand Up @@ -840,6 +842,9 @@ void appTaskControllerExample() async {
case UserTaskState.done:
userTask.executor.stop();
break;
case UserTaskState.notified:
print('Task id: ${userTask.id} was clicked in the OS.');
break;
default:
//
break;
Expand Down
25 changes: 13 additions & 12 deletions carp_mobile_sensing/example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -297,24 +297,25 @@ class LocalStudyProtocolManager implements StudyProtocolManager {
// phone,
// );

// Add two app tasks with notifications.
// Add app tasks with notifications.
//
// These App Tasks are added for demo purpose and you should see notifications
// on the phone. However, nothing will happen when you click on it.
// See the PulmonaryMonitor demo app for a full-scale example of how to use
// the App Task model.

// Add a task 1 minute after deployment and make a notification.
// protocol.addTaskControl(
// ElapsedTimeTrigger(elapsedTime: const IsoDuration(seconds: 30)),
// AppTask(
// type: BackgroundSensingUserTask.ONE_TIME_SENSING_TYPE,
// title: "Elapsed Time - App Task",
// measures: [Measure(type: DeviceSamplingPackage.DEVICE_INFORMATION)],
// notification: true,
// ),
// phone,
// );
// Add a task after deployment and make a notification.
protocol.addTaskControl(
ElapsedTimeTrigger(elapsedTime: const IsoDuration(seconds: 30)),
AppTask(
type: BackgroundSensingUserTask.ONE_TIME_SENSING_TYPE,
title: "Elapsed Time Trigger - App Task",
description: 'Collection of Device Information.',
measures: [Measure(type: DeviceSamplingPackage.DEVICE_INFORMATION)],
notification: true,
),
phone,
);

// // Add a cron job every day at 11:45
// protocol.addTaskControl(
Expand Down
2 changes: 1 addition & 1 deletion carp_mobile_sensing/lib/carp_mobile_sensing.json.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
part of carp_mobile_sensing;
part of 'carp_mobile_sensing.dart';

bool _fromJsonFunctionsRegistered = false;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of data_managers;
part of '../data_managers.dart';

/// A very simple data manager that just "uploads" the data to the
/// console (i.e., prints it). Used mainly for testing and debugging purposes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of data_managers;
part of '../data_managers.dart';

class FileDataManagerFactory implements DataManagerFactory {
@override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of data_managers;
part of '../data_managers.dart';

/// Retrieve and store [StudyProtocol] json definitions on the device's local
/// file system.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of data_managers;
part of '../data_managers.dart';

class SQLiteDataManagerFactory implements DataManagerFactory {
@override
Expand Down
2 changes: 1 addition & 1 deletion carp_mobile_sensing/lib/domain/app_task.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of domain;
part of 'domain.dart';

/// A task that notifies the app when it is triggered.
///
Expand Down
3 changes: 2 additions & 1 deletion carp_mobile_sensing/lib/domain/data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
* Use of this source code is governed by a MIT-style license that can be
* found in the LICENSE file.
*/
part of domain;

part of 'domain.dart';

/// A [Data] object holding a link to a file.
@JsonSerializable(fieldRename: FieldRename.none, includeIfNull: false)
Expand Down
2 changes: 1 addition & 1 deletion carp_mobile_sensing/lib/domain/data_endpoint.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of domain;
part of 'domain.dart';

/// Specify an endpoint where a [DataManager] can upload data.
@JsonSerializable(fieldRename: FieldRename.none, includeIfNull: false)
Expand Down
3 changes: 2 additions & 1 deletion carp_mobile_sensing/lib/domain/data_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
* Use of this source code is governed by a MIT-style license that can be
* found in the LICENSE file.
*/
part of domain;

part of 'domain.dart';

/// Contains CAMS data type definitions similar to CARP Core [CarpDataTypes].
class CAMSDataType {
Expand Down
2 changes: 1 addition & 1 deletion carp_mobile_sensing/lib/domain/device_configurations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of domain;
part of 'domain.dart';

/// An online service which works as a "software device" in a protocol.
@JsonSerializable(fieldRename: FieldRename.none, includeIfNull: false)
Expand Down
2 changes: 1 addition & 1 deletion carp_mobile_sensing/lib/domain/device_info.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of domain;
part of 'domain.dart';

/// Provides (static) information about the local device.
///
Expand Down
11 changes: 8 additions & 3 deletions carp_mobile_sensing/lib/domain/domain.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
/*
* Copyright 2018-2022 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.
*/

/// The CAMS implementation of the core CARP domain classes like
/// [StudyProtocol], [TaskConfiguration], and [Measure].
/// Also hold JSON serialization and deseralization logic to handle seraialization
/// of the domain objects.
/// Also hold JSON logic to handle de/serialization of the domain objects.
library domain;

import 'dart:io';
Expand All @@ -22,7 +28,6 @@ part 'smartphone_deployment.dart';
part 'app_task.dart';
part 'tasks.dart';
part 'triggers.dart';
// part 'datum.dart';
part 'data.dart';
part 'data_types.dart';
part 'device_info.dart';
Expand Down
3 changes: 2 additions & 1 deletion carp_mobile_sensing/lib/domain/sampling_configurations.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
* Use of this source code is governed by a MIT-style license that can be
* found in the LICENSE file.
*/
part of domain;

part of 'domain.dart';

/// A sampling configuration that saves the last time it was sampled.
@JsonSerializable(fieldRename: FieldRename.none, includeIfNull: false)
Expand Down
2 changes: 1 addition & 1 deletion carp_mobile_sensing/lib/domain/smartphone_deployment.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of domain;
part of 'domain.dart';

/// Contains the entire description and configuration for how a smartphone
/// device participates in the deployment of a study on a smartphone.
Expand Down
2 changes: 1 addition & 1 deletion carp_mobile_sensing/lib/domain/study_description.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of domain;
part of 'domain.dart';

@JsonSerializable(fieldRename: FieldRename.none, includeIfNull: false)
class StudyDescription extends Serializable {
Expand Down
2 changes: 1 addition & 1 deletion carp_mobile_sensing/lib/domain/study_protocol.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of domain;
part of 'domain.dart';

/// A mixin holding smartphone-specific data for a [SmartphoneStudyProtocol] and
/// [SmartphoneDeployment].
Expand Down
2 changes: 1 addition & 1 deletion carp_mobile_sensing/lib/domain/tasks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* found in the LICENSE file.
*/

part of domain;
part of 'domain.dart';

/// Signature of Dart function that have no arguments and returns no data.
typedef VoidFunction = void Function();
Expand Down
3 changes: 2 additions & 1 deletion carp_mobile_sensing/lib/domain/transformers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
* Use of this source code is governed by a MIT-style license that can be
* found in the LICENSE file.
*/
part of domain;

part of 'domain.dart';

/// Signature of a data transformer.
typedef DataTransformer = Data Function(Data);
Expand Down
Loading
Loading