CARP Mobile Sensing Framework in Flutter

CARP pub package GitHub MIT License Documentation arXiv Discord

This library contains the core Flutter package for the CARP Mobile Sensing (CAMS) framework. Supports cross-platform (iOS and Android) mobile sensing.

For an overview of all CAMS packages, see CARP Mobile Sensing in Flutter. See the CARP Mobile Sensing Documentation for how to install & configure, use, and extend CAMS.

Usage

To use this plugin, add carp_core and carp_mobile_sensing as dependencies in your pubspec.yaml file.

dependencies:
  carp_core: ^latest
  carp_mobile_sensing: ^latest

Configuration

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

First, CAMS rely on the flutter_local_notifications plugin. So if you want to use App Tasks and notifications you should configure your app to the platforms it supports and configure your app for both Android and iOS. There are a lot of details in configuring for notifications — especially for Android — so read this carefully.

Second, to support data sampling in the background, CAMS rely on the flutter_background plugin. This only works on Android and requires adding permissions to the AndroidManifest.xml and specifying the appropriate foregroundServiceType for your use case.

Please see the Install and Configure page for details for Android and iOS.

Important

Other CAMS sampling packages require additional permissions in the AndroidManifest.xml or Info.plist files. See the documentation for each package.

Documentation

The Dart API doc describes the different libraries and classes.

The CARP Mobile Sensing Documentation has detailed documentation on the CARP Mobile Sensing Framework, including the overall software architecture, the domain model, how to use it to create a study protocol, how to extend it, and an overview of the available measure types.

Note

More scientific documentation of CAMS is available in the following papers:

Please use these references in any scientific papers using CAMS.

Examples of Configuring and Using CAMS

There is a very simple example app which shows how a study protocol can be configured and used to create, deploy, and run a study. This app just prints the collected data to the console. There is also a range of different examples on how to create a study to take inspiration from.

However, the CARP Mobile Sensing App provides a MUCH better example of how to use the framework in a Flutter MVVM architecture, including good documentation of how to do this.

Below is a small primer in the use of CAMS for a very simple sampling study running locally on the phone. This example is similar to the example app app.

A CAMS study can be configured, deployed, executed, and used in different steps:

  1. Define a SmartphoneStudyProtocol.
  2. Add a study based on this protocol to the SmartPhoneClientManager.
  3. Deploy the study and resume sampling.
  4. Use the generated data (called measurements) locally in the app or specify how and where to store or upload it using a DataEndPoint.
  5. Control the execution of the study, like calling resume or pause on the client, the study, or individual probes.

Creating a study protocol and deploying it

Below is a simple example of how to set up a protocol that samples step counts, ambient light, screen events, and battery events.

import 'package:carp_core/carp_core.dart' hide Smartphone;
import 'package:carp_mobile_sensing/carp_mobile_sensing.dart';

// Create a protocol collecting steps, light, and screen and battery events
// from the phone and store collected measurements in a local SQLite database
final phone = Smartphone();
final protocol =
    SmartphoneStudyProtocol(
        ownerId: 'AB',
        name: 'Tracking steps, light, screen, and battery',
        dataEndPoint: SQLiteDataEndPoint(),
      )
      ..addPrimaryDevice(phone)
      ..addTaskControl(
        DelayedTrigger(delay: const Duration(seconds: 10)),
        BackgroundTask(
          measures: [
            Measure(type: SensorSamplingPackage.STEP_EVENT),
            Measure(type: SensorSamplingPackage.AMBIENT_LIGHT),
            Measure(type: DeviceSamplingPackage.SCREEN_EVENT),
            Measure(type: DeviceSamplingPackage.BATTERY_STATE),
          ],
        ),
        phone,
      );

// Create and configure a client manager for this phone.
await SmartPhoneClientManager().configure();

// Create a study based on the protocol.
var study = await SmartPhoneClientManager().addStudyFromProtocol(protocol);

// Deploy the study.
await SmartPhoneClientManager().tryDeployment(
  study.studyDeploymentId,
  study.deviceRoleName,
);

// Resume sampling.
SmartPhoneClientManager().resume();

// Listening on the measurements stream.
SmartPhoneClientManager().measurements.listen((measurement) {
  // Do something with the measurement, e.g. print the json.
  print(toJsonString(measurement));
});

// Pause sampling.
SmartPhoneClientManager().pause();

// Resume sampling again.
SmartPhoneClientManager().resume();

// Dispose the client. Can not be used anymore.
SmartPhoneClientManager().dispose();

The above example defines a simple SmartphoneStudyProtocol which will use a Smartphone as a primary device for data collection and store data in a SQLite database locally on the phone using a SQLiteDataEndPoint. Sampling is configured using a DelayedTrigger which triggers a BackgroundTask containing four different Measures. When this study is resumed, the background task is started after a delay of 10 seconds, and will continue to collect the four measures until paused.

Sampling can be configured in very sophisticated ways, by specifying different types of devices, task controls, triggers, tasks, measures, and sampling configurations. See the CAMS documentation for an overview and more details.

Minimal example

In the example above, the client manager is configured, the protocol is added, and sampling is started. This can actually be done in one line of code, like this:

SmartPhoneClientManager().configure().then(
  (_) => SmartPhoneClientManager()
      .addStudyFromProtocol(
        SmartphoneStudyProtocol.local(
          name: 'Tracking steps, light, screen, and battery',
          measures: [
            Measure(type: SensorSamplingPackage.STEP_EVENT),
            Measure(type: SensorSamplingPackage.AMBIENT_LIGHT),
            Measure(type: DeviceSamplingPackage.SCREEN_EVENT),
            Measure(type: DeviceSamplingPackage.BATTERY_STATE),
          ],
        ),
      )
      .then(
        (study) => SmartPhoneClientManager()
            .tryDeployment(study.studyDeploymentId, study.deviceRoleName)
            .then((_) => SmartPhoneClientManager().resume()),
      ),
);

This will start the sampling immediately (and not delayed as above) and data is stored in the SQLite database.

Using the generated data

The generated data can be accessed and used in the app. Access to data is done by listening on the measurements stream from the client manager:

// Listening on the data stream and print them as json.
SmartPhoneClientManager()
    .measurements
    .listen((measurement) => print(toJsonString(measurement)));

Note that measurements is a Dart Stream and you can hence apply all the usual stream operations to the collected measurements, including sorting, mapping, reducing, and transforming measurements.

Data stored in the SQLite database is accessed via the file system, as explained in the Data Managers.

Controlling the sampling of data

Data sampling can be controlled on runtime by resuming, pausing, and disposing sampling. For example, calling SmartPhoneClientManager().pause() would pause all data sampling running on the client. Calling resume() would resume it again.

Calling SmartPhoneClientManager().dispose() would dispose of the client manager. Once dispose is called, you cannot call resume or pause sampling anymore. This method is typically used in the Flutter dispose() method.

Extending CAMS

CAMS is designed to be extended in at least four ways: (i) adding new triggers, (ii) adding new data sampling capabilities and support for new devices, (iii) adding a new data manager for storing and uploading data, and (iv) adding data transformers for different data formats and data privacy protection.

Please see the documentation on how to extend CAMS.

Features and bugs

Please read about existing issues and file new feature requests and bug reports at the issue tracker.

License

This software is copyright (c) the Technical University of Denmark (DTU) and is part of the Copenhagen Research Platform. This software is available 'as-is' under a MIT license.

Libraries

carp_mobile_sensing
This library contains the software architecture for the CARP Mobile Sensing (CAMS) framework implemented in Flutter. Supports cross-platform (iOS and Android) mobile sensing.
domain
This library hold the CAMS-specific extensions and implementation of the carp_core domain classes like SmartphoneStudyProtocol and PeriodicTrigger.
infrastructure
The infrastructure library provide on-phone implementations of CAMS services like the SmartphoneDeploymentService deployment service and the SQLiteDataManager data manager.
runtime
The runtime layer is the main entry point to CAMS and holds the SmartPhoneClientManager, SmartphoneStudyControllers with a SmartphoneDeploymentExecutor for each running study, DeviceController with DeviceManagers for each connected device, and a SamplingPackageRegistry for registering sampling packages and their supported devices and probes.
sampling_packages
The sampling package library holds the built-in sampling packages: