Legacy (v1) vs Inform (v2)
The same Validic Mobile SDKs are used by both Legacy (v1) and Inform (v2) API customers. To make the documentation easier to access, the Mobile Getting Started Guides and class documentation are hosted on our Inform (v2) documentation site.
The API documentation, however, is different between Legacy (v1) and Inform (v2). If you are an Inform (v2) API customer, you must use the Inform API documentation.
If you are a Legacy (v1) API customer, be sure to go back to the Legacy API documentation.
Prerequisites
To get started, download the Android framework from the Validic Mobile portal.
The Validic Mobile library supports Android 5 - 11 (API levels 21 - 30) and requires Android Studio to compile.
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.
Validic user can be provisioned using the Validic API, documentation is available for both Legacy API (V1) and Inform API (V2) APIs. The credentials needed are a Validic user ID, an organization ID and a user access token. The user access token value you provide to the SDK is the "user access token" value if you use the Legacy (V1) API. The user access token value you provide to the SDK is the "mobile token" value if you use the Inform (V2) API.
System Requirements
A minimum sdk of 21 is supported (you may choose a higher value):
android {
defaultConfig {
minSdkVersion 21
}
}
Installation
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' }
}
}
Individual modules
The library is divided into separate modules. The Shared module is required. Other modules should be added to your project based on the functionality you wish to support in your app.
Add the desired dependencies to your app’s build.gradle file as follows:
dependencies {
...
//Required for all projects
implementation ':[email protected]'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.retrofit2:retrofit:2.8.2'
implementation 'com.squareup.retrofit2:converter-gson:2.8.2'
implementation 'com.jakewharton.threetenabp:threetenabp:1.2.4'
implementation 'androidx.work:work-runtime:2.4.0'
// For bluetooth functionality
implementation ':[email protected]'
implementation 'com.polidea.rxandroidble2:rxandroidble:1.11.0'
//for VitalSnap functionality
implementation ':[email protected]'
//for Samsung Health functionality
implementation ':[email protected]'
implementation files('libs/samsung-health-data-1.5.0.aar')
...
}
Finally initialize the library within your Application class’s onCreate:
@Override
public void onCreate() {
super.onCreate();
ValidicMobile.getInstance().initialize(this);
}
If using the bluetooth module, a global error handler will be registered via: RxJavaPlugins.setErrorHandler(). This is the fallback error handler called by RxJava.
If you want to customize this handler, it can be overridden by passing a new instance to ValidicBluetoothManager.setErrorHandler()
before calling ValidicMobile.getInstance().initialize()
:
@Override
public void onCreate() {
super.onCreate();
// Optionally override global RxJava error handler
ValidicBluetoothManager.setErrorHandler(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
//Custom error handling here
}
});
// Required initialization
ValidicMobile.getInstance().initialize(this);
}
Please review the RxJava 2.x error handling documentation for more information about this handler.
Logging
Logging can be enabled using the static methods in the ValidicLog
class.
ValidicLog.globalLoggingEnabled(true);
By default, nothing is logged. To start logging update the LogLevel
to the appropriate level.
ValidicLog.setLogLevel(ValidicLog.DEBUG);
or set your own logging instance
ValidicLog.setLogger(new Logger(){
@Override
void log(int level, String tag, String msg){
Timber.log(level, msg);
}
}
Session
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 valid session is required in order to use any of the modules in the Validic SDK.
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();
Record types
There are seven different subclasses of Record that will be collected by Validic
Biometrics
– comprised of a user’s biometric health data such as blood pressure, cholesterol, heart rate, and blood and hormone levels.Diabetes
– comprised of a user’s blood glucose and hormone levels related to diabetes treatment and management.Fitness
– comprised of a user’s activities that are undertaken with the express purpose of exercising. These activities have a defined duration (time, distance, elevation, etc.)Nutrition
– comprised of a user’s activities related to calorie intake and consumption and nutritional information (such as fat, protein, carbohydrates, sodium, etc.)Routine
– comprised of a user’s activities that occur regularly throughout the day, without the specific goal of exercise, for example calories burned and consumed, steps taken, stairs climbed. These activities are aggregate throughout the day.Sleep
– comprised of a user’s measurements related to the length of time spent in various sleep cycles, as well as number of times woken during the night.Weight
– comprised of a user’s weight and body mass.
Record Identifiers
The Validic Mobile SDK uses log_id
(for the Inform/V2 API) or activity_id
(for the Legacy/V1 API) as the unique identifier for a given record. These IDs are created by the mobile SDK before submission to the server.
The Validic server also assigns an id
(for the Inform/V2 API) or _id
(for the Legacy/V1 API) for each unique record. It is recommended to use the server-side id
/ _id
to identify and/or de-duplicate records post-submission.
Submit records
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);
Listener
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.
Bluetooth
Overview
The Validic Mobile SDK supports Bluetooth Low Energy devices via three integration methods, as follows:
Bluetooth module - custom | Bluetooth module - generic | Lifescan module |
---|---|---|
A custom integration via the Bluetooth module is most the common integration method. These devices are assigned unique peripheralIDs and use custom Bluetooth Profiles. | A generic integration via the Bluetooth module is available for glucose meters only. These devices are supported through | The Lifescan module is a wrapper used alongside LifeScan's Mobile Connectivity Kit. These devices are supported via separate classes than the Bluetooth module devices. |
Readings from custom or generic Bluetooth devices supported in the Bluetooth module can be captured and uploaded to Validic with BluetoothPeripheralController
.
Please refer to the LifeScan section for details on how to use the Lifescan module.
Peripherals
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 withassets://
) 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:
<div class="highlight">
List<BluetoothPeripheral> supportedPeripherals = BluetoothPeripheral.getSupportedPeripherals();
for(BluetoothPeripheral peripheral : supportedPeripherals) {
Log.v("Test", "Found peripheral: " + peripheral.getName());
}
</div>
Generic Peripherals
You can communicate with glucose meters that are supported via the Bluetooth generic Glucose Profile using peripheralID = 1000
Unlike custom-supported peripherals, this generic peripheral has generic object information. You can substitute in your own device name, image, and instructions within your app so that end users see device information that's applicable to the device you wish to support.
{
"codes": [
{
"code": "",
"language": "text"
}
]
}
Permissions
The validicmobile-ble
artifact automatically adds the following permissions to the consuming application's mergedAndroidManifest.xml
:
- android.permission.BLUETOOTH
- android.permission.BLUETOOTH_ADMIN
- android.permission.FOREGROUND_SERVICE
android.permission.ACCESS_COARSE_LOCATION
or android.permission.ACCESS_FINE_LOCATION
must be added by the consumer.
Android 10
- Starting with Android 10,
android.permission.ACCESS_FINE_LOCATION
is required by the OS. android.permission.ACCESS_BACKGROUND_LOCATION
must be requested along withandroid.permission.ACCESS_FINE_LOCATION
in order for Passive Bluetooth reading to succeed if the device is inDOZE
mode for devices running api 26 or later
Android 11
- Starting with Android 11, on devices running api >= Android 11 (api 30), the
android.permission.ACCESS_BACKGROUND_LOCATION
must be granted manually by end user's in the application settings. To navigate to the application settings use the following code
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.parse("package:" + getApplication().getPackageName())); intent.addCategory(Intent.CATEGORY_DEFAULT); startActivityForResult(intent, BLE_BACKGROUND_CODE);
Pair
Check if a BluetoothPeripheral
requires pairing by calling:
BluetoothPeripheral peripheral = // ...
peripheral.requiresPairing()
If it does, the user must pair the peripheral 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
Read
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) {
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);
Auto-submission of Records
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);
Passive Read
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 versions >= 26 a notification channel must be created.
As of Android 26 background scanning without a service will be the default. Please see BluetoothLeScanner documentation for more information.
If a foreground service is preferred it can still be used by setting:
PassiveBluetoothManager.getInstance().setPreferForegroundService(true)
Note that on Android version >= 26 a notification channel must be created.
If the application is targeting at least android-28, the FOREGROUND_SERVICE
permission must be added to the application’s manifest as well
<manifest>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
</manifest>
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();
Listener
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:
PassiveBluetoothManager.BluetoothListener listener = new PassiveBluetoothManager.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
}
};
Note: The PassiveBluetoothManager uses a WeakReference to manage the passive listener. Activities and Fragments may be destroyed and then recreated when coming from the Background
into the foreground. It is recommended to have a singleton maintain a strong reference to your listener or to set the listener in `Activity.onCreate` or `Fragment.onAttach`
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());
Considerations
Agamatrix
The Agamatrix Jazz Wireless 2 glucose meter, supported via a custom Bluetooth integration (peripheralID = 32
), requires an authentication key, which is provided by Agamatrix, in order to communicate with the meter. To configure your Agamatrix authentication key for use with the Agamatrix meter in the Validic Mobile SDK:
- Create a file named
agamatrix.license
- File contents should be your Agamatrix key without the hex prefix notation
0x
. For example, if your key is0x011234567890987654321
then your file contains011234567890987654321
. - Add the
agamatrix.license
file in the application's/app/src/main/assets/
folder.
CVS Health
The CVS Health Advanced Bluetooth Glucose Meter, supported via a custom Bluetooth integration (peripheralID = 33
), requires an authentication key, which is provided by Agamatrix, in order to communicate with the meter. To configure your Agamatrix authentication key for use with the CVS Health meter in the Validic Mobile SDK:
- Create a file named
cvs_advanced.license
- File contents should be your Agamatrix key without the hex prefix notation
0x
. For example, if your key is0x055234567890987654987
then your file contains055234567890987654987
. - Add the
cvs_advanced.license
file in the application's/app/src/main/assets/
folder.
Passive Read
- Passive reading is not automatically restarted after device reboot. Your application must be launched or a BootReceiver registered to start passive reading.
- For Android > 5.0 internal OS heuristics govern the frequency of scanning. This could cause some peripherals not to be discovered in the background.
- To prevent duplicate records passive reading will not take readings from a peripheral if that peripheral has been read from within the last 15 seconds.
There are several situations where passive bluetooth reading is cancelled and resumed at a later time:
- When the system becomes low on memory, passive reading will be cancelled. When the system frees enough memory it will relaunch passive reading and begin scanning again.
- When the end user swipes away the application from the Recent Tasks list, passive reading will be cancelled; 1 Second later, passive reading will automatically restart again.
- When the end user turns off bluetooth passive reading will be cancelled and will be automatically restarted once bluetooth is turned back on.
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.
VitalSnap (OCR)
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.
Overview
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.
Peripherals
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.
ValidicOCRActivity
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
}
}
}
ValidicOCRController
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);
Runtime unit selection
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.
For the Zewa 11110 thermometer, you can specify Celsius or Fahrenheit at runtime for a given reading. If no unit is provided, Fahrenheit 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);
ValidicOCRFragment
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.
View Structure
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 relevant part of the overlay is guaranteed 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.
Listener
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 Lifecycle
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();
Google Fit
This project integrates Google Fit with the Validic Mobile Aggregator to passively collect data on behalf of an end user. Validic ensures that our Mobile SDK makes use of the minimal scopes needed for our supported data types. Additionally, when using Google Fit version com.google.android.gms:play-services-fitness:19.0.0
or lower, Validic does not request or use any scopes indicated as sensitive or restricted by Google.
With the upcoming Google Fit version com.google.android.gms:play-services-fitness:20.0.0
, all read scopes will be restricted and will require completing Google’s sensitive scope verification or restricted scope verification and security assessment to retrieve data. Please see Google's announcement for further details: https://developers.google.com/fit/improvements
Be aware that Google has an extensive and potentially lengthy verification process. Google manages their own verification process and it is subject to change at any time at their discretion. It is your responsibility to review, understand, and follow Google’s verification process and provide Google with all information they request before sharing your application publicly. Validic does not provide direct support for Google’s verification process, however, Google’s Verification FAQ is detailed and provides you with the information you’ll need to complete the process. See the Customer Requirements section below for highlights on setting up, developing, and verifying for Google Fit.
Customer Requirements
Google Fit is available for Inform (V2) Validic customers. If you are a Legacy (V1) customer and are interested in Google Fit, please reach out to your Validic Client Success Manager.
Validic’s Google Fit integration works with Google Fit for Android. Google Fit for Android uses Google’s OAuth API for accessing user data. There is setup that must occur before you implement Google Fit into your mobile project so that your users can consent to sharing and share their data successfully:
Before you start development, in Google Api Console you must:
- Create Google Services OAuth 2.0 Client IDs
- Verify your domain ownership
- Configure your user consent screen
After completing the above setup, you can start development using the instructions in this tutorial. While you are developing, testing can occur with Google user accounts that are registered to the same domain as the mobile project.
After development and testing are complete and before you launch your app, you will need to submit a request to Google for Oauth API Verification. There are certain instances where this may not be required (see Google’s FAQ for details).
Once you submit your verification request, you may be required to provide some or all of the following:
- Application Homepage detailing your use of requested scopes
- Privacy Policy and Terms & Conditions
- Application Demo Video showing the user consent workflow in your app
- Application Name, Logo, and/or other branding elements
Google dictates their own verification process so you may be asked to provide additional information as well. See Verification Requirements for more information. Be sure to respond to Google’s requests as quickly as possible to minimize delays in getting your verification approved.
Installation
Add aggregator.aar
, aggregator-fit.aar
and validicmboile-shared.aar
to the libs/
folder of your application
Dependencies
Add the libraries and their dependencies
dependencies{
//Google fit dependencies
implementation 'com.google.android.gms:play-services-fitness:17+'
implementation 'com.google.android.gms:play-services-auth:17+'
//validic dependencies
implementation files('libs/validicmobile-shared.aar')
implementation files('libs/aggregator-fit.aar')
implementation files('libs/aggregator.aar')
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
}
Initialization
The ValidicFitManager
will be initialized at app startup and will immediately start listening for previously subscribed data types. It is recommended that you set a listener on the ValidicFitManager
during your applicatin onCreate()
method
private final ValidicFitManager.AggregatorListener fitListener = new AggregatorManager.AggregatorListener() {
@Override
public void onRecords(@NotNull Map<Record.RecordType, Integer> summary) {
// summary of number of records collected and queued for submission to the Validic Inform API
}
@Override
public void onException(@NotNull AggregatorException exception) {
// An exception has occurred. Check if the exception can be handled by the sdk
if (exception.getHasResolution()) {
// handle the resolution using an activity
exception.handleResolution(activity, 999);
}
//otherwise display error
}
};
Request permissions
Before collecting any data from Google Fit, a Google Account must be associated with the ValidicFitManager
, and the end user must authorize the app to collect data on their behalf.
Get previously granted permissions
To check if permissions have already been granted the hasDataAccess(Set<DataType> dataTypes)
method can be used
Set<DataType> dataTypes = new HashSet<>();
dataTypes.add(DataType.TYPE_STEP_COUNT_DELTA);
Map<DataType, Boolean> = ValidicFitManager.INSTANCE.hasDataAccess(dataTypes);
The map returned from hasDataAccess(Set<DataType> dataTypes)
associates a DataType
with true, if a valid Google account exists and permission has previsouly been granted, or false otherwise.
Request new permissions
To request permission from the end user to authorize data collection, first add result handling to your activity
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
ValidicFitManager.INSTANCE.handlePermissionResult(this, requestCode, resultCode, data);
}
Next, the requestPermissions(Activity, Set<DataType>, Integer, Integer, PermissionHandler)
method can be used to authorize your application
// MyActivity
Set<DataType> dataTypes = new HashSet<>();
dataTypes.add(DataType.STEP_COUNT_DELTA);
ValidicFitManager.INSTANCE.requestPermissions(MyActivity.this, dataTypes, new AggregatorManager.PermissionsHandler<DataType>() {
@Override
public void onResults(Map<DataType, Boolean> dataTypes) {
// do work with results.
}
});
Android 10
For the Android client Apps that target API 28 the permission below is required in the AndroidManifest.xml. The Validic SDK will add this permission to its manifest so that it will be merged with the client when they add our library to their application.
<uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
This permission is required to subscribe to the following data types:
- com.google.step_count.delta
- com.google.step_count.cumulative
- com.google.step_count.cadence
- com.google.activity.segment
- com.google.activity.exercise
For apps targeting Android 10, this permission must be requested from the user at runtime
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.ACTIVITY_RECOGNITION)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
}
ActivityCompat.requestPermissions(thisActivity,
arrayOf(Manifest.permission.ACTIVITY_RECOGNITION),
MY_PERMISSIONS_REQUEST_ACTIVITY_RECOGNITION);
Manage subscriptions
After Permissions have been granted for a DataType
the ValidicFitManager
can be used to add subscriptions to data change events from Google Fit. Data will automatically will queued for submission to the Validic API when internet is available on the device
Set<DataType> dataTypes = new HashSet<>();
dataTypes.add(DataType.TYPE_STEP_COUNT_DELTA);
ValidicFitManager.INSTANCE.subscribe(dataTypes);
To unregister from receiving data update events use the ValidicFitManager
to unsubscribe
ValidicFitManager.INSTANCE.unsubscribe(DataType.TYPE_STEP_COUNT_DELTA)
Get a list of currently subscribed DataType
s
List<DataType> subscriptions = ValidicFitManager.INSTANCE.currentSubscriptions()
Currently Supported DataTypes
- DataType.TYPE_STEP_COUNT_DELTA
- DataType.TYPE_WEIGHT
- DataType.TYPE_HEART_RATE_BPM
- DataType.TYPE_CALORIES_EXPENDED
- DataType.TYPE_MOVE_MINUTES
- DataType.TYPE_DISTANCE_DELTA
- DataType.TYPE_NUTRITION
Records collected are automatically submitted to the Validic Inform API and a summary of records processed will be sent to any AggregatorListener#onRecords(summary)
registered using ValidicFitManager.INSTANCE.setListener(fitListener)
For an example of setting a listener see Initialization
Fetch historical data
Validic provides the ability to query six months of data for a subset of data types provided by Google Fit using fetchHistory().
One historical set is available:
- HistoryType.Summary - SUMMARIES (step) data
Logout
To remove all subscriptions and log an end user out simply call
ValidicFitManager.INSTANCE.disconnect()
Samsung Health
The Validic Mobile library provides a simple way to read and upload data from Samsung Health to Validic. Through the SHealthManager
you can subscribe to specific Samsung Health data types and automatically upload them to Validic in the background as new data is recorded.
General setup
Approval Required
The Samsung Health integration requires pre-approval for Samsung's Device SDK.
Currently, Samsung is going through an update to better support their partners and, for that reason, they are not accepting applications for the Partner Apps Program. We will keep this section up to date as we hear any updates from the Samsung team.
You can download the aar from the Samsung Health website: https://developer.samsung.com/health/android/overview.html#SDK-Download
In order to test, you must enable developer mode in the Samsung Health app on your phone. For instructions on how to enable developer mode please see Samsung's website: https://developer.samsung.com/health/android/data/guide/dev-mode.html
Note: Starting with Samsung Health app version 6.11.0.061 (released August 2020), in order to gain access to Samsung Health data, with or without developer mode enabled, you must first be approved by Samsung and receive a Samsung dev access key. Prior versions of the Samsung Health app do not require the dev access key when the Samsung Health app is in developer mode.
You can learn more about requesting access via Samsung's website here: https://developer.samsung.com/health/android/overview.html#Partner-Apps-Program
Before you can use the Samsung Health features of the library, be sure to import the Samsung Digital Health Healthdata aar into your project by adding the following line to your gradle dependencies:
implementation files('libs/samsung-health-data-1.5.0.aar')
Manage subscriptions
Samsung provides several data types that can be subscribed to for notification when data changes.
The available data types are:
- 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.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
- com.samsung.shealth.nutrition
Unsupported types (see https://developer.samsung.com/health/android/release-note.html for more information): com.samsung.health.food_info com.samsung.health.food_intake
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.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;
com.samsung.shealth.nutrition" />
Subscription sets
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:
- Routine - Daily step data
- com.samsung.shealth.step_daily_trend
- Diabetes - Blood glucose and hba1c data
- com.samsung.health.blood_glucose
- com.samsung.health.hba1c
- Weight - Weight and height data
- com.samsung.health.weight
- Fitness - Exercise data
- com.samsung.health.exercise
- Sleep - Sleep and sleep stage data
- com.samsung.health.sleep
- com.samsung.health.sleep_stage
- Nutrition - Food and nutrition data
- com.samsung.health.nutrition
- com.samsung.health.caffeine_intake
- com.samsung.health.water_intake
- Blood Pressure - Blood pressure data
- com.samsung.health.blood_pressure
The group of data types for each subscription set can be found using:
SHealthSubscription.permissionStringsForSubscriptionSet(SHealthSubscription.SHealthSubscriptionSet.FITNESS);
Request permissions
Before a subscription can be created the related permissions must be granted.
Requesting permissions will immediately display a Samsung Health dialog through which the user may grant or deny requested permissions.
The result of the user’s selections will be delivered through an SHealthManager.SHealthListener
callback; specifically the onPermissionChange
method will be called.
Please read SHealth Listener for more information regarding registering and implementing this callback.
Request permissions:
SHealthManager.getInstance().requestPermissionsForDataTypes("com.samsung.health.blood_glucose", "com.samsung.health.blood_pressure");
Subscribe to permissions
Be sure to request permissions as described above before subscribing.
Subscribing to Samsung 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().requestSubscriptionsForDataTypes("com.samsung.health.blood_glucose", "com.samsung.health.blood_pressure");
or as part of a subscription set:
SHealthManager.getInstance().
requestSubscriptionsForDataTypes(SHealthSubscription.permissionStringsForSubscriptionSet(SHealthSubscription.SHealthSubscriptionSet.FITNESS));
To start the Samsung 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 If the application is targeting at least android-28, the FOREGROUND_SERVICE
permission must be added to the application’s manifest as well
<manifest>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
</manifest>
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().requestSubscriptionsForDataTypes(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()
.requestSubscriptionsForDataTypes(
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();
Fetch historical data
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:
- SHealthSubscription.SHealthHistoricalSet.FITNESS - Workouts data
- SHealthSubscription.SHealthHistoricalSet.ROUTINE - Summaries (step) data
To execute a historical fetch use the SHealthManager.getInstance()
to perform the historical fetch operation
SHealthManager.getInstance().fetchHistoricalSets(SHealthSubscription.SHealthHistoricalSet.FITNESS);
SHealth Listener
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.
}
}
Note: The SHealthManager uses a WeakReference to manage the passive listener. Activities and Fragments may be destroyed and then recreated when coming from the Background into the foreground. It is recommended to have a singleton maintain a strong reference to your listener or to set the listener each time in Activity.onCreate
or Fragment.onAttach
Example
A typical use of the Samsung 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();
}
}
};
Notes
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.getInstance().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.getInstance().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.
LifeScan
Approval Required
The LifeScan integration requires pre-approval for LifeScan's OneTouch Mobile Connectivity Kit (MCK). Please reach out to Validic Support at [email protected] if you are interested in LifeScan.
Installation
Add OneTouchMobileConnectivityKit.aar
, validicmobile_lifescan.aar
, and validicmobile-shared.aar
, to the libs/
folder of your project.
Licensing
To properly install the license, please start by: 1) Making sure your file is named onetouch-license.json
1) Moving the file into your project so that its location looks like the following: app/src/main/assets/onetouch-license.json
1) Making sure your application’s app id matches the key Android App Identifiers
in the license file.
Note: Modifying the content of the AAR or license file in anyway will invalidate the license.
Dependencies
Add these dependency references to your build.gradle
.
//Validic dependencies
implementation files('libs/validicmobile-shared.aar')
implementation files('libs/validicmobile_lifescan.aar')
implementation 'com.jakewharton.threetenabp:threetenabp:1.2.0'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'
implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31'
//LifeScan dependencies
implementation files('libs/OneTouchMobileConnectivityKit.aar')
implementation 'com.androidx.core:1.2.0'
implementation 'com.jakewharton.timber:timber:4.7.0'
implementation "com.fasterxml.jackson.core:jackson-databind:2.9.8"
implementation 'com.getkeepsafe.relinker:relinker:1.2.2'
Initialization
Initialize the ValidicMobile SDK as detailed in the Installation section at the beginning of this guide. Once initialized and and active Session
has been started and instance of ValidicLifeScan
can be retrieved:
ValidicLifeScan.getInstance(context);
Scan
Scanning can be started with scan()
:
ValidicLifeScan.getInstance(context).scan(TimeUnit.SECONDS.toMillis(timeout), new LifescanScanningListener() {
@Override
public void onScanComplete(final List<OneTouchDevice> devices, OneTouchError error) {
}
@Override
public void onDeviceDiscovered(OneTouchDevice device) {
}
});
Scanning can be stopped with:
ValidicLifeScan.getInstance(context).stopScan()
Pair
In order to read from a device the device must first be paired. Pairing requests require a previously discovered device from scan()
.
ValidicLifeScan.getInstance(context).pair(discoveredDevice, new LifescanPairingListener() {
@Override
public void onSuccess(OneTouchDevice device) {
}
@Override
public void onError(OneTouchDevice device, OneTouchError error) {
}
});
Paired devices can be retrieved with getPairedDevices()
List<OneTouchDevice> pairedDevices = ValidicLifeScan.getInstance(context).getPairedDevices();
Read
Once a device is paired a read can be requested:
ValidicLifeScan.getInstance(context).read(mSelectedDevice, new LifescanReadListener() {
@Override
public void onConnected(OneTouchDevice device) {
}
@Override
public void onResults(OneTouchDevice device, final List<Diabetes> records, OneTouchError error) {
// records may be an empty list if there were not any new measurements to read.
}
});
Note that previously read records are not returned to the same paired device again.
Subsequent reads from the same device without taking new measurements will return an empty list of records.
Passive Read
Background reads can be performed with devices that have been successfully paired. To do so a foreground Service will be started that handles device connections and reads.
Reading can be started by calling:
ValidicLifeScan.getInstance(context).startBackgroundRead(params);
By passing nulls a default Notification will be used. A Notification can be provided, but note that if providing a custom notification its PendingIntent must be configured correctly to offer a stop action from the notification, or the service must be stopped manually elsewhere.
Here is an example of building a Notification that has a PendingIntent action that will stop the background read service:
private void startBackgroundReadService(Context context) {
String notificationId = UUID.randomUUID().toString();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel(notificationId, "LifeScan Background " +
"Notification", NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
Notification notification = getBackgroundReadNotification(context, notificationId);
ValidicLifeScan.getInstance(context).startBackgroundRead(new NotificationParams(123123, notification));
}
private Notification getBackgroundReadNotification(Context context, String notificationChannelId) {
Intent serviceIntent = new Intent(context, LifescanBackgroundReadService.class);
serviceIntent.putExtra(LifescanBackgroundReadService.INTENT_KEY_STOP, true);
PendingIntent stopServicePendingIntent = PendingIntent.getService(context, 0, serviceIntent, 0);
return new NotificationCompat.Builder(context, notificationChannelId)
.addAction(R.drawable.stop_action_icon_visible_pre_nougat, "Stop Service", stopServicePendingIntent)
.setContentTitle("Custom Content Title")
.setContentText("Helpful notification content.")
.setColor(ContextCompat.getColor(context, R.color.your_accent_color_perhaps))
.setSmallIcon(R.drawable.ic_icon_notification)
.build();
}
To stop background reading call:
ValidicLifeScan.getInstance(context).stopBackgroundRead();
DeviceManager
To access properties and methods from the Lifescan device manager, use getNativeManager()
OneTouchDeviceManager deviceManager = ValidicLifescan.getInstance(context).getNativeManager();
OneTouchManagerState state = deviceManager.getManagerState();
if(state == READY){
//do something
}
This can be used to add listeners for events as well.
ValidicLifeScan.getInstance(context).getNativeManager().addListener(new OneTouchManagerListener(){
@Override
void onStateChanged(OneTouchDeviceManagerState newState){
if(newState == READY){
//do something
}
}
});
Updated 13 days ago
What's Next
Review the class documentation online:
Shared module |
Bluetooth module |
Google Fit module |
Samsung Health module (requires approval from Samsung) |
VitalSnap (OCR) module |