In order to use the Validic Mobile Library, you will need a valid organization id and valid user credentials.
If you do not already have an organization id, you will need to first apply for one.
After your organization is set up, you will need a Validic user id and access token.
You can create a new user by referring to the API documentation.
A minimum sdk of 19 is supported (you may choose a higher value):
android {
compileSdkVersion 22
buildToolsVersion "23"
defaultConfig {
minSdkVersion 19
targetSdkVersion 21
}
}
And to use VitalSnap requires a minimum sdk version of 21:
android {
compileSdkVersion 22
buildToolsVersion "23"
defaultConfig {
minSdkVersion 21
targetSdkVersion 24
}
}
Copy the aars
and place it in your project’s libs folder:
If your project does not currently contain a libs folder, simply create the folder.
Next open your app’s build.gradle file and add the following lines to it:
android{
...
repositories {
...
flatDir{ dirs 'libs' }
}
}
Starting with version 1.6.0 the library has been divided into 4 separate modules.
Add the desired dependencies to your app’s build.gradle file:
dependencies {
...
//For all projects
implementation ':validicmobile-shared@aar'
implementation 'com.android.support:support-v4:+'
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'com.koushikdutta.async:androidasync:2.1.7'
// For bluetooth
implementation ':validicmobile-ble@aar'
implementation 'com.polidea.rxandroidble2:rxandroidble:1.7.1'
//for VitalSnap
implementation ':validicmobile-ocr@aar'
//for Samsung Health
implementation ':validicmobile-shealth@aar'
implementation 'android.arch.work:work-runtime:1.0.0-alpha06'
implementation files('libs/samsung-digital-health-healthdata-1.2.1.jar')
...
}
Finally initialize the library within your Application class’s onCreate:
@Override
public void onCreate() {
super.onCreate();
ValidicMobile.getInstance().initialize(this);
}
As part of the initialize() call above a global error handler is registered: RxJavaPlugins.setErrorHandler(). This is the fallback error handler called by RxJava.
This global error handler can be overridden by setting your own after calling ValidicMobile.getInstance().initialize(this)
:
@Override
public void onCreate() {
super.onCreate();
// Required initialization
ValidicMobile.getInstance().initialize(this);
// Optionally override global RxJava error handler
RxJavaPlugins.setErrorHandler(
new Consumer<Throwable>() {
@Override
public void accept(Throwable error) {
// Handle errors as desired
}
}
);
}
Please review the RxJava 2.x error handling documentation for more information about this handler.
Session
is a singleton object and must be accessed by its getInstance()
method. The Session instance stores a Validic User and all pending Record
uploads.
A Validic user can be provisioned using the Validic API. Further documentation is available for both the Legacy V1 API and the new Inform API.
You will need to provision the user on your server. The mobile app could then authenticate to the server and retrieve the needed Validic credentials.
To use an existing Validic User, create a User object and provide it to the startSessionWithUser(User)
method.
User user = new User("Your Organization ID",
"A Validic User ID",
"A Validic User Access Token");
Session.getInstance().startSessionWithUser(user);
User data is persisted between app launches but is deleted if endSession()
is called.
Session.getInstance().endSession();
There are seven different subclasses of Record that will be collected by Validic
Choose a data type to test with and construct a Record
object:
Weight testRecord = new Weight();
testRecord.setWeight(new BigDecimal("200"));
Records can be submitted individually:
Weight record = new Weight();
record.setWeight(new BigDecimal("200"));
Session.getInstance().submitRecord(record);
or as a group:
List<Record> records = new ArrayList<>();
Weight record1 = new Weight();
Weight record2 = new Weight();
records.add(record1);
records.add(record2);
Session.getInstance().submitRecords(records);
When Session
uploads a record it will notify the stored SessionListener
. To receive these notifications, register a SessionListener
by calling setSessionListener(SessionListener)
:
SessionListener listener = new SessionListener() {
@Override
public void didSubmitRecord(Record record) {
// If you want to store a copy locally, now would be the time
}
@Override
public void didFailToSubmitRecord(Record record, Error error) {
Toast.makeText(getApplicationContext(), "Failed to upload record!", Toast.LENGTH_LONG).show();
}
};
Session.getInstance().setSessionListener(listener)
If a 400 error is returned from the server, the record will be discarded and SessionListener.didFailToSubmitRecord(Record, Error)
will be called. If the record is submitted successfully, didSubmitRecord(Record)
will be called.
A BluetoothPeripheral
represents Bluetooth peripheral models that can be discovered or read from by BluetoothPeripheralController
.
The class contains various information to be displayed to the user:
getName()
– Returns a String representing the customer recognizable name of the peripheral.getImageUrl()
– Returns either a local image path (prefixed with assets://
) or a remote image path to an example peripheral image.getPairingInstruction()
– Returns a String telling the user how to pair the peripheral, if the peripheral requires pairing.getInstruction()
– Returns a String telling the user how to initialize the reading process with the peripheral.getReadingInstruction()
– Returns a String telling the user what to do during the reading process.To retrieve a List of supported perpherals simply call:
List<BluetoothPeripheral> supportedPeripherals = BluetoothPeripheral.getSupportedPeripherals();
for(BluetoothPeripheral peripheral : supportedPeripherals) {
Log.v("Test", "Found peripheral: " + peripheral.getName());
}
Check if a BluetoothPeripheral
requires pairing by calling:
BluetoothPeripheral peripheral = // ...
peripheral.requiresPairing()
If it does, the user must pair the perpheral before they can take a reading.
BluetoothPeripheral peripheral = // Choose a perpheral from the supported perpherals list
BluetoothPeripheralControllerListener listener = new BluetoothPeripheralControllerListener(){
@Override
public void onFail(BluetoothPeripheralController peripheralController, BluetoothPeripheral peripheral, BluetoothPeripheralController.BluetoothError error) {
// Tell the user to retry the pairing process
}
@Override
public void onSuccess(BluetoothPeripheralController peripheralController, BluetoothPeripheral peripheral, List<Record> records) {
// The peripheral is now paired
// Records received during pairing are not submitted
}
@Override
public void onPeripheralDiscovered(final BluetoothPeripheralController peripheralController, BluetoothPeripheral peripheral) {
// The peripheral is currently pairing...
}
};
BluetoothPeripheralController controller = new BluetoothPeripheralController();
controller.pairPeripheral(peripheral, listener);
String pairingInstructions = peripheral.getPairingInstruction();
// Display the pairing Instructions to the user
Once you are ready to read from a peripheral, the process is fairly similar to the pairing process.
You’ll want to first show the peripheral’s instructions and eventually show the reading instructions once onPeripheralDiscovered
is called.
BluetoothPeripheral peripheral = // The peripheral you want to read from
BluetoothPeripheralControllerListener listener = new BluetoothPeripheralControllerListener(){
@Override
public void onPeripheralDiscovered(final BluetoothPeripheralController peripheralController, BluetoothPeripheral peripheral) {
// Display the reading Instructions to the user
}
@Override
public void onFail(final BluetoothPeripheralController peripheralController, BluetoothPeripheral peripheral, BluetoothPeripheralController.BluetoothError error) {
super.readingFailedForPeripheral(peripheralController, peripheral, error);
switch (error) {
case BluetoothError.BluetoothTurnedOff:
Toast.makeText(getApplicationContext(), "Your bluetooth is off!", Toast.LENGTH_LONG).show();
break;
case BluetoothError.NoUser:
Toast.makeText(getApplicationContext(), "You have not started the session yet!", Toast.LENGTH_LONG).show();
break;
case BluetoothError.Cancelled:
Toast.makeText(getApplicationContext(), "Reading has been cancelled", Toast.LENGTH_LONG).show();
break;
}
Log.e("Error", error.getMessage());
}
@Override
public boolean onSuccess(final BluetoothPeripheralController peripheralController, BluetoothPeripheral peripheral, List<Record> records) {
// If you want to auto-submit records, return true
return true;
// else if you want to require the user to confirm the record, return false
// return false;
}
};
String instruction = peripheral.getInstruction();
// Display the instruction to the user
BluetoothPeripheralController controller = new BluetoothPeripheralController();
controller.readFromPeripheral(peripheral, listener);
You have the option to automatically submit records as soon as they are captured, or you can wait for user confirmation before submitting the record. For auto submission, return true
inside your onSuccess()
method. If you return false
you MUST call submitRecord()
or the record will be discarded.
Session.getInstance().submitRecord(record);
The ValidicMobile library supports reading from bluetooth peripherals without any user interaction once a device has been successfully paired.
The PassiveBluetoothManager
manages background reads and interactions with any BluetoothPeripheralController
objects in use.
Reading or pairing a peripheral in the foreground will cancel any in progress readings from the background and will restart monitoring in the background once all bluetooth interaction in the foreground has finished.
To set peripherals to be read in the background use the PassiveBluetoothManager.getInstance()
singleton as such:
Set<BluetoothPeripheral> peripherals = new HashSet<>();
peripherals.add(BluetoothPeripheral.getPeripheralForID(1);
peripherals.add(BluetoothPeripheral.getPeripheralForID(2);
peripherals.add(BluetoothPeripheral.getPeripheralForID(3);
PassiveBluetoothManager.getInstance().setPassivePeripherals(peripherals);
To start the service in the foreground. For Android versions >= 25 a notification must be supplied to allow the background scanning to continue to run while the app is not in the foreground.
Note that on Android version >= 26 a notification channel must be created.
Please review documentation regarding Doze for more information.
Set<BluetoothPeripheral> peripherals = new HashSet<>();
peripherals.add(BluetoothPeripheral.getPeripheralForID(1);
peripherals.add(BluetoothPeripheral.getPeripheralForID(2);
peripherals.add(BluetoothPeripheral.getPeripheralForID(3);
if (Build.VERSION_CODES.O <= Build.VERSION.SDK_INT) {
// Create Notification Channel
NotificationChannel channel = ...
}
// Create a notification
Notification notification = ...
NotificationParams params = new NotificationParams(1, notification);
PassiveBluetoothManager.getInstance().setPassivePeripherals(peripherals, params);
To stop monitoring peripherals in the background set the background peripherals to null or an empty set
PassiveBluetoothManager.getInstance().setPassivePeripherals(null);
To stop monitoring peripherals via the Notification when using a foreground service a PendingIntent should be used to notify a BroadcastReceiver to take the appropriate action:
Register the BroadcastReceiver in the Manifest:
<receiver android:name="com.validic.mobile.ble.BluetoothServiceStopReceiver">
<intent-filter>
<action android:name="com.validic.mobile.ble.STOP_BLUETOOTH_SERVICE" />
</intent-filter>
</receiver>
Add a PendingIntent to be used when the notification is interacted with:
Intent intent = new Intent(BluetoothServiceStopReceiver.ACTION_STOP_BLUETOOTH_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 200, intent, 0);
// Create a notification that uses the PendingIntent
Notification notification = new NotificationCompat.Builder(context)
.addAction(icon, message, pendingIntent)
// Continue setting up notification
.build();
Records will be automatically uploaded as they are read.
In order to receive events from the the PassiveBluetoothManager, use one of the following two methods.
In both cases a PassiveBluetoothManager.BluetoothListener
must be created in order to receive the events:
BluetoothPassiveManager.BluetoothListener listener = new BluetoothPassiveManager.BluetoothListener(){
@Override
public void onSuccess(BluetoothPeripheral peripheral, List<Record> records) {
// Records received in the background are automatically uploaded
}
@Override
public void onFail(BluetoothPeripheral peripheral, BluetoothPeripheralController.BluetoothError error) {
// Reading failed in the background
}
@Override
public void onPeripheralDiscovered(BluetoothPeripheral peripheral){
// A peripheral was discovered and we have setup a connection
}
@Override
public void onBackgroundStart(){
// Background scanning has begun
}
@Override
public void onBackgroundStop(){
// Background scanning has stopped
}
};
This listener can either be set on the PassiveBluetoothManager
instance:
PassiveBluetoothManager.getInstance().setBluetoothListener(listener);
or a PassiveBluetoothReceiver
can be registered using the LocalBroadcastManager
PassiveBluetoothReceiver receiver = new PassiveBluetoothReceiver(listener);
LocalBroadcastManager.getInstance(context).registerReceiver(receiver, PassiveBluetoothReceiver.getIntentFilter());
There are several situations where passive bluetooth reading is cancelled and resumed at a later time:
When passive bluetooth reading is cancelled, any current passive readings will be cancelled, and the PassiveBluetoothManager.BluetoothListener will receive onCancelled for each of the peripherals.
OCR provides the capability to obtain readings from devices without requiring Bluetooth integration. The recognition process is managed by an instance of ValidicOCRController
.
A simple example application, “MiniApps/VitalSnap”, is provided to illustrate the OCR API.
An instance of the ValidicOCRController
class is used to manage the recognition process. An OCRPeripheral
represents the peripheral being scanned. The controller is initialized with a peripheral object.
The recognition process involves a fragment that contains the camera preview and an overlay image. The fragment must be injected into your view.
OCR processing begins as soon as the fragment is injected into the view. An instance of ValidicOCRResultListener
must be registered to receive intermediate and final results. The camera capture session ends when the fragment is paused.
OCRPeripheral
represents peripheral models that can be processed by OCR.
A peripheral object contains various properties which can be displayed to the user:
name
- Name of the peripheral comprised of the manufacturer name and model number.imageURL
- URL for an image of the peripheral.Validic provides an activity to encapsulate the OCRFragment. It will perform the necessary permission checking for Android versions > 23. To start an instance of the activity start by using an intent and Activity.startForResult();
public void startOCRActivity() {
Intent intent = new Intent(this, ValidicOCRactivity.class);
OCRPeripheral peripheral = OCRPeripheral.getPeripheralForId(1); // One Touch
intent.putExtra(ValidicOCRActivity.PERIPHERAL_ID, peripheral.getPeripheralID());
}
Optionally a File path can added to the request if needed:
File f = new File(getFilesDir(), "image.png");
intent.putExtra(ValidicOCRActivity.IMAGE_PATH f.getAbsolutePath());
Then start the activity for a result
activity.startActivityForResult(intent, ValidicOCRActivity.ACTION_READ_OCR);
To receive a converged result in the same activity you launched the ValidicOCRActivity
override OnActivityResult()
protected override void OnActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ValidicOCRActivity.ACTION_READ_OCR) {
if (resultCode. == Activity.RESULT_OK) {
OCRPeripheral peripheral = (OCRPeripheral) data.getSerializableExtra(ValidicActivity.Peripheral_KEY);
Record record = (Record) data.getSerializableExtra(ValidicActivity.RECORD_KEY);
String s = data.getStringExtra(ValidicActivity.IMAGE_KEY);
File f = new File(s);
Uri uri = Uri.fromFile(f);
if (uri != null) {
bitmap = BitmapFactory.decodeStream(contentResolver.openInputStream(uri));
// Bitmap is now in memory
}
} else if (resultCode == ValidicOCRActivity.ERROR_WRITING_FILE) {
OCRPeripheral peripheral = (OCRPeripheral) data.getSerializableExtra(ValidicActivity.Peripheral_KEY);
Record record = (Record) data.getSerializableExtra(ValidicActivity.RECORD_KEY);
} else {
// Error with activity
}
}
}
The ValidicOCRController
requires an OCRPeripheral
for its initializers.
To obtain an OCRPeripheral
, you may choose from a list of all available devices:
List<OCRPeripheral> allSupportedPeripherals = OCRPeripheral.getSupportedPeripherals();
or if you know the specific peripheral type that you want:
final static int ONETOUCH_ULTRAMINI = 1;
OCRPeripheral onetouchPeripheral = OCRPeripheral.getPeripheralForOCRPeripheralType(ONETOUCH_ULTRAMINI);
Once a peripheral is obtained, construct the ValidicOCRController
and assign it an instance of ValidicOCRResultListener
:
ValidicOCRController ocrController = ValidicOCRController.initWithOCRPeripheral(peripheral);
ocrController.setListener(listener);
For any glucose meter in our lineup of supported meters, you can now specify mmol/l or mg/dL at runtime for a given reading. If no unit is provided, mg/dL is assumed.
An example using the ValidicOCRActivity
:
OCRPeripheral peripheral = OCRPeripheral.getPeripheralForId(1); // One Touch
Intent intent = new Intent(this, ValidicOCRActivity.class);
intent.putExtra(ValidicOCRActivity.PERIPHERAL_ID, peripheral.getPeripheralID());
intent.putExtra(ValidicOCRActivity.GLUCOSE_UNIT_KEY, Unit.Glucose.MMOLL);
An example using the ValidicOCRController
:
ValidicOCRController ocrController = ValidicOCRController.initWithOCRPeripheral(peripheral, Unit.Glucose.MMOLL);
The camera preview and overlay are contained in a fragment that must be injected with an instance of ValidicOCRController
. Ensure your view contains a FrameLayout, preferably fullscreen in size, and give it a referencable id such as activity_ocr_fragment_container
.
Injection Example:
ocrController.injectOCRFragment(getFragmentManager().beginTransaction(),
R.id.activity_ocr_fragment_container)
.commit();
This will immediatly begin the OCR process.
The preview and overlay are handled by the library, but showing intermediate results are not. You must provide a fullscreen container for the fragment in order for the OCR functionality to be reliable. The relevent part of the overlay is gaurenteed to be no larger than half the height of the screen. Should you choose to show any other views during the OCR process, please restrict them to the lower half of the screen.
During OCR processing, methods on an instance of ValidicOCRResultListener
will be invoked.
public void didProcessResult(VitalSnapResult vitalSnapResult)
is invoked for each camera frame captured and provides intermediate results. The VitalSnapResult
object contains the current recognized string. The result string can be displayed to the user as an indication of what portion of the display is not being recognized. Depending on the peripheral, the result string may contain linefeeds representing multiple lines being recognized. The result string also indicates whether glare is affecting OCR of a particular digit by returning the *
char, and therefore can be helpful feedback for the user to avoid negative effects of glare on the reading.
Log.v(TAG, "Partial result: " + vitalSnapResult.toString());
public void didCompleteReading(Record record, Bitmap bitmap, ValidicOCRPeripheral validicOCRPeripheral)
is invoked when OCR processing has completed with sufficient confidence.
if (validicOCRPeripheral.getType() == Peripheral.PeripheralType.GlucoseMeter) {
Diabetes diabetesRecord = (Diabetes) record;
Log.v(TAG, "Blood glucose captured: " + diabetesRecord.getBloodGlucose().toString());
}
The value received from the listener should be verified by the user and then submitted to the Validic server:
// After verification, queue the record and the image to be uploaded to the server
Session.getInstance().submitRecord(record, bitmap);
The listener is passed a Record
subclass appropriate for the peripheral and the matching cropped preview image with embedded additional metadata. The recognized values returned in the record should be visually validated by the user. The cropped preview image can be displayed to the user to validate the recognized values before uploading to the server.
OCR processing commences when the ocr fragment is injected into your view.
Processing is stopped when the fragment is paused or a final value has been converged. If no value has been converged on, the fragment will resume processing onResume. To restart or to take additional readings with the same peripheral, simply call restartOCR on the ValidicOCRController
.
ocrController.restartOCR();
The Validic Mobile library provides a simple way to read and upload data from S Health to Validic. Through the SHealthManager
you can subscribe to specific S Health data types and automatically upload them to Validic in the background as new data is recorded.
You can download the jar from the Samsung Health website: http://developer.samsung.com/health
In order to test you must enable developer mode in the S Health app on your phone. As of shealth sdk version 1.2.1, you enable developer mode by going to the More->Settings->About S Health and tapping the version number until “(Developer Mode)” is displayed next to it.
Note: In order to gain access to S Health data without developer mode enabled you must first be approved by Samsung.
You can request access here: http://developer.samsung.com/health/apiaccess
Before you can use the S Health features of the library, be sure to import the Samsung Digital Health Healthdata jar into your project by adding the following line to your gradle dependencies:
compile files('libs/samsung-digital-health-healthdata-1.2.1.jar')
Samsung provides several data types that can be subscribed to for notification when data changes.
The available data types are:
NOTE: Data types that are going to be used in your application must be added to the AndroidManifest.xml.
<application>
// Rest of app
<meta-data android:name="com.samsung.android.health.platform_type" android:value="rel" />
<meta-data
android:name="com.samsung.android.health.permission.read"
android:value=" com.samsung.health.blood_glucose;
com.samsung.health.blood_pressure;
com.samsung.health.body_temperature;
com.samsung.health.caffeine_intake;
com.samsung.health.exercise;
com.samsung.health.food_info;
com.samsung.health.food_intake;
com.samsung.health.hba1c;
com.samsung.health.heart_rate;
com.samsung.health.oxygen_saturation;
com.samsung.health.sleep;
com.samsung.health.sleep_stage;
com.samsung.health.uv_exposure;
com.samsung.health.water_intake;
com.samsung.health.weight;
com.samsung.shealth.step_daily_trend" />
Data types are grouped into logical sets; SHealthSubscription.SubscriptionSet
is an Enum
that groups several data types together to register for related data types.
The available subscription sets are:
The group of data types for each subscription set can be found using:
SHealthSubscription.permissionStringsForSubscriptionSet(SHealthSubscription.SHealthSubscriptionSet.FITNESS);
Subscribing to S Health updates only needs to be done once for a user. The subscriptions will be persisted across app launches in the Session
object.
Data types can be subscribed to individually:
SHealthManager.getInstance().addSubscriptionsForDataTypes("com.samsung.health.blood_glucose", "com.samsung.health.blood_pressure");
or as part of a subscription set:
SHealthManager.getInstance().
addSubscriptionsForDataTypes(SHealthSubscription.permissionStringsForSubscriptionSet(SHealthSubscription.SHealthSubscriptionSet.FITNESS));
When creating a subscription a WorkManager worker will be scheduled to run every ~15 minutes to check for updated readings. This Worker will run even if the application is not running. If readings must be reported immediately while your app is in the background, please use the foreground service approach detailed below.
To start the S Health service in the foreground. For Android versions >= 26 a notification must be supplied to allow the background scanning to continue to run while the app is not in the foreground.
Please note that on Android version >= 26 a notification channel must be created:
Please review documentation regarding Doze for more information.
Individual subscription:
if (Build.VERSION_CODES.O <= Build.VERSION.SDK_INT) {
// Create Notification Channel
NotificationChannel channel = ...
}
// Create a notification
Notification notification = ...
NotificationParams params = new NotificationParams(1, notification);
SHealthManager.getInstance().addSubscriptionsForDataTypes(param, "com.samsung.health.blood_glucose", "com.samsung.health.blood_pressure");
As a subscriptions set:
if (Build.VERSION_CODES.O <= Build.VERSION.SDK_INT) {
// Create Notification Channel
NotificationChannel channel = ...
}
// Create a notification
Notification notification = ...
NotificationParams params = new NotificationParams(1, notification);
SHealthManager.getInstance()
.addSubscriptionsForDataTypes(
params,
SHealthSubscription.permissionStringsForSubscriptionSet(SHealthSubscription.SHealthSubscriptionSet.FITNESS)
);
To stop monitoring peripherals via the Notification when using a foreground service a PendingIntent should be used to notify a BroadcastReceiver to take the appropriate action:
Register the BroadcastReceiver in the Manifest:
<receiver android:name="com.validic.mobile.shealth.SHealthServiceStopReceiver">
<intent-filter>
<action android:name="com.validic.mobile.shealth.STOP_SHEALTH_SERVICE" />
</intent-filter>
</receiver>
Add a PendingIntent to be used when the notification is interacted with:
Intent intent = new Intent(SHealthServiceStopReceiver.ACTION_STOP_SHEALTH_SERVICE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 200, intent, 0);
// Create a notification that uses the pending intent
Notification notification = new NotificationCompat.Builder(context)
.addAction(icon, message, pendingIntent)
// Continue setting up notification
.build();
Validic provides the ability to query six months of data for a subset of data types provided by Samsung Health by querying
a group of SHealthSubscription.SHealthHistoricalSet
Two historical sets are available:
To execute a historical fetch use the SHealthManager.getInstance()
to perform the historical fetch operation
SHealthManager.getInstance().fetchHistoricalSets(SHealthSubscription.SHealthHistoricalSet.FITNESS);
To listen for events from SHealth, a SHealthListener
can be set to receive events from SHealth.
SHealthManager.getInstance().setSHealthListener(new SHealthListener() {
@Override
public void onError(final SHealthError error) {
// An error specific to SHealth has occured. Check the error type for additional actions.
}
@Override
public void onPermissionChange(String[] acceptedPermissions, String[] deniedPermissions) {
// Permissions were requested as part of the workflow.
}
@Override
public void onRecords(Map<Record.RecordType, Integer> summary) {
// Records were gathered by an SHealth data change.
}
@Override
public void onHistoricalFetch(Map<RecordType, Integer> summary) {
// Records were fetched from SHealth history.
}
}
A typical use of the S Health component would be to create a Switch that adds the required subscriptions when toggled on and removes them when toggled off. Example:
new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
if (isChecked) {
SHealthManager.getInstance().addSubscriptionsForDataTypes(
SHealthSubscription.permissionStringsForSubscriptionSet(SHealthSubscription.SHealthSubscriptionSet.FITNESS));
} else {
SHealthManager.getInstance().removeAllSubscriptions();
}
}
};
In order to resume listening for subscriptions upon app launch you must call observeCurrentSubscriptions()
inside your application’s onCreate function:
public class YourApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
ValidicMobile.initialize(context);
SHealthManager.getInstance().observeCurrentSubscriptions();
}
}
In order to resume listening for subscriptions upon device reboot, you must add a BroadcastReceiver to your manifest:
public class BootReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){
ValidicMobile.initialize(context);
SHealthManager.getInstance().observeCurrentSubscriptions();
}
}
}
In your manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- ... -->
<receiver android:name=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Calling Session.getInstance().endSession()
will remove all S Health subscriptions and stop listening for new data.