Step 1. Add the JitPack repository to your build file
Add it in your root settings.gradle at the end of repositories:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
Add it in your settings.gradle.kts at the end of repositories:
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
Add to pom.xml
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
Add it in your build.sbt at the end of resolvers:
resolvers += "jitpack" at "https://jitpack.io"
Add it in your project.clj at the end of repositories:
:repositories [["jitpack" "https://jitpack.io"]]
Step 2. Add the dependency
dependencies {
implementation 'com.github.niclabs:adkintun-mobile-middleware:'
}
dependencies {
implementation("com.github.niclabs:adkintun-mobile-middleware:")
}
<dependency>
<groupId>com.github.niclabs</groupId>
<artifactId>adkintun-mobile-middleware</artifactId>
<version></version>
</dependency>
libraryDependencies += "com.github.niclabs" % "adkintun-mobile-middleware" % ""
:dependencies [[com.github.niclabs/adkintun-mobile-middleware ""]]
Android Middleware for performing mobile sensing and monitoring. Originally created for the Adkintun Mobile project, it is released under the Apache Open Source License to be used by developers in their own software projects.
The following requirements guided the actual design and development of the middleware:
The general design of the middleware is inspired by the AWARE Framework, and some of the code for the different monitors was based on that project, given that they already had resolved many of the issues related to Android development. However that framework did not fulfill all of our requirements, motivating the development the present library.
The structure of the main entities in the middleware is shown on Figure above, where the architecture of the central classes follows the observer and factory patterns. A general description of the different entities is provided below.
Monitor
, defining the general structure for all monitoring classes, which will perform the task of listening to OS events. This class extends from the Android Service class, thus allowing each monitor to run as a daemon of the system.Events
of the Operating System. Events define different aspects of a monitoring task. For instance, the Traffic
monitor can observe events of mobile traffic, WiFi traffic or application traffic, and a developer using the library may choose to activate a different one depending on the application.Listener
can be attached to a monitor, in order to be notified of new observations from an event,Observation
object, carrying data about the event as well as the timestamp, and event type (a code to identify the event).Persistent
, meaning they can be saved to a local database (SQLite for now) if desired,Serializable
, meaning they can be exported to different formats (JSON, CSV, etc.).Proxy
objects, which can listen to multiple monitors in order to notify their own listeners of a specific context. One example of these objects is the ConnectivityStatusProxy
which compares two consecutive connectivity observations and notifies its listeners of a change in connectivity or roaming status.Scheduling of notifications is performed to ensure that observations arrive in the correct order, and periodical NTP synchronization is implemented to ensure that the reported timestamp of the events is correct.
The library only has two software dependencies, included as jars under the libs/
directory (we know is not good practice but maven is a pain)
TelephonyObservation
(can be GSM or CDMA) is provided for each change, except on the case of signal power, where the instance is kept as long as there are no antena changes and only the signal strenght Sample
is updated.DeviceInfo
provides a summary of all device information (IMEI, baseband, model, brand, etc.)A full example of a working application is provided under the examples/
folder in the code. However, here is a quick start.
Monitor
as you would bind to any other Android Service, controllers simplify the task. Here is how you create a Traffic
monitor controllerController<TrafficListener> trafficController = Traffic.bind(Traffic.class, context);
trafficController.listen(trafficListener, true);
Bundle bundle = new Bundle();
/* Configure the sampling frequency to 20 seconds */
bundle.putInt(Traffic.TRAFFIC_UPDATE_INTERVAL_EXTRA, 20);
trafficController.activate(Monitor.TRAFFIC_MOBILE | Monitor.TRAFFIC_WIFI, bundle);
onMobileTrafficChange
and onWiFiTrafficChange
.Below is a full example Activity
package cl.niclabs.adkmobile;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import cl.niclabs.adkmobile.monitor.Monitor;
import cl.niclabs.adkmobile.monitor.Monitor.Controller;
import cl.niclabs.adkmobile.monitor.Traffic;
import cl.niclabs.adkmobile.monitor.data.TrafficObservation;
import cl.niclabs.adkmobile.monitor.listeners.TrafficListener;
public class MonitorActivity extends Activity implements TrafficListener {
private static final String TAG = "MonitorActivity";
/* Monitor controllers make easier binding to a Monitor */
private Controller<TrafficListener> trafficController;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* Bind controller to the current application context */
trafficController = Traffic.bind(Traffic.class, this);
/* Append this class as listener */
trafficController.listen(this, true);
Bundle bundle = new Bundle();
/* Configure the sampling frequency to 20 seconds */
bundle.putInt(Traffic.TRAFFIC_UPDATE_INTERVAL_EXTRA, 20);
/* Activate controller for monitoring mobile and WiFi traffic */
trafficController.activate(Monitor.TRAFFIC_MOBILE | Monitor.TRAFFIC_WIFI, bundle);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
/* Unbind from the monitor and destroy the service if there are
* no other classes bound to it */
trafficController.unbind();
}
@Override
public void onMobileTrafficChange(TrafficObservation trafficState) {
/* The state will be serialized to JSON */
Log.i(TAG, "Received new mobile traffic state "+trafficState);
}
@Override
public void onWiFiTrafficChange(TrafficObservation trafficState) {
Log.i(TAG, "Received new WiFi traffic state "+trafficState);
}
@Override
public void onApplicationTrafficChange(TrafficObservation trafficState) {
// This will never be used
}
}
The permissions required for each monitor are specified in the code documentation. The following configuration is required in the AndroidManifest.xml
of the application in order to activate clock synchronization (implemented on cl.niclabs.adkmobile.services.ClockService
) and persistence with Sugar ORM.
<!-- Required by connectivity service -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!-- For access to NTP server -->
<uses-permission android:name="android.permission.INTERNET" />
<application android:name="cl.niclabs.adkmobile.AdkintunMobileApp"><!-- android:name is required to activate clock synchronization and persistance !-->
<!-- Give permission to the Traffic monitor. It must be added for each service required in the platform !-->
<service android:name="cl.niclabs.adkmobile.monitor.Traffic" ></service>
<!-- Give permission to Connectivity monitor and ClockService for time synchronization -->
<service android:name="cl.niclabs.adkmobile.monitor.Connectivity" />
<service android:name="cl.niclabs.adkmobile.services.ClockService" />
</application>
The same configuration as Sugar ORM is required on the manifest to enable persistance
<!-- Database configuration -->
<meta-data android:name="DATABASE" android:value="mydb.db" />
<meta-data android:name="VERSION" android:value="1" />
<meta-data android:name="QUERY_LOG" android:value="true" />
<!-- Do not change, required to store monitor observations !-->
<meta-data android:name="DOMAIN_PACKAGE_NAME" android:value="cl.niclabs.adkmobile.monitor.data" />
In order to listen to boot status changes, the following code must be added inside <application></application>
on the manifest.
<!-- Register receiver in order to monitor device boot state -->
<receiver android:name="cl.niclabs.adkmobile.monitor.Device"
android:enabled="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.ACTION_SHUTDOWN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>