The WearOS Sensors library is an Android WearOS library that allows to collect data from the IMU sensors (i.e., accelerometer and gyroscope), the magnetometer, the heart rate, and the GPS of an Android WearOS smartwatch (if the corresponding sensor is available in the device).
This library can be used to build WearOS applications that are the counterpart of smartphone applications built with the nativescript-wearos-sensors plugin (for the NativeScript framework). The smartphone application counterpart can request to start/stop the data collection on the smartwatch, and then receive the collected data from the smartwatch.
Important
An application built with this library is completely useless if there is not a counterpart application built with the nativescript-wearos-sensors plugin installed in the paired smartphone. In other words, the smartwatch can not work by itself alone. It requires for a smartphone to work.
The data collection can be started both from the smartwatch and from the paired smartphone. In addition, the library offers a way to communicate with the smartphone by sending messages.
The WearOS Sensors library uses and extends the functionality of the Android Background Sensors library, and therefore, it is safe to carry out the data collection in the background (i.e., when the app is not in the foreground, or the smartwatch is idle).
To install the library you have to add the dependency in your build.gradle
:
dependencies {
implementation 'io.github.geotecinit:wear-os-sensors:1.3.0'
}
The library has the following requirements:
- An Android WearOS smartwatch running WearOS 1.0 (API level 23) or higher. In addition, the smartwatch must be paired with a smartphone with the counterpart application installed.
Important
Both applications (smartwatch and smartphone apps) must have the same application id. If that's not the case, the applications will not be able to interact.
Tip
Don't forget to check the requirements of nativescript-wearos-sensors too.
The library has been tested in the following WearOS versions:
- WearOS 2.33 (Android 9 - API 28):
- TicWatch Pro 3 GPS
- WearOS 3.5 (Android 11 - API 30):
- TicWatch Pro 3 GPS
- TicWatch Pro 5
- WearOS 4 (Android 13 - API 33):
- Samsung Watch4
The library offers two main features:
- Sensor data collection: it can be started/stopped from the paired smartphone or from the smartwatch itself. Some permissions must be added to the AndroidManifest of the smartwatch device depending on which sensor you want to collect data from:
Accelerometer, gyroscope and magnetometer
If your app targets an API level 31 or higher and you will to collect data from the sensors at a sampling rate higher than 200Hz, the following permission must be added to the manifest:
<uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS" />
Heart rate
You must add the following permission to the manifest:
<uses-permission android:name="android.permission.BODY_SENSORS" />
In addition, if your app runs on a WearOS 4+ smartwatch (Android 13 - API 33), add the following permission:
<uses-permission android:name="android.permission.BODY_SENSORS_BACKGROUND" />
Location
You must add the following permission to the manifest:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
In addition, if your app runs on a WearOS 3+ smartwatch (Android 13 - API 33), add the following permission:
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
- Messaging: it allows to send and receive simple messages between both devices.
The library allows to collect data from the accelerometer, gyroscope, magnetometer, heart rate and GPS sensors of the smartwatch device. For the data collection, the application in the smartwatch acts as a companion application, where the main application is the on in the smartphone. This means that the smartphone is who instructs the smartwatch to start/stop the data collection, even when is the smartwatch who wants to start/stop the data collection.
Before going deeper with the data collection, we have to talk about permissions.
In order to access to the data of the heart rate and the GPS sensors, the user has to grant some permissions. The library handles this situation (i.e., when permissions are required), and launches a notification to warn the user that some permissions need to be granted. We can differentiate two main steps in the process:
- Check if permissions are required:
- If the data collection is started using the paired smartphone, the check is automatic. You have to do nothing!
- If the data collection is started using the smartwatch, you need to do the check using the
PermissionsManager.launchPermissionsRequestIfNeeded()
method.
- Request the required permissions: the library handles mostly of the process by you, but you still have to do execute some steps:
- Create an Activity: it will be used by the library to request the permissions. This will allow you to define a UI where some information can be given prior to the permissions request.
- In your activity:
- Create an instance of the
PermissionsRequestHandler
class. - Provide a callback using the
PermissionsRequestHandler.onPermissionsResult()
method. The callback will be called with the result of the request, which can be used to update the UI. After 1 second, the activity will close. - Override the
Activity.onRequestPermissionsResult
and inside it, callPermissionsRequestHandler.handleResult()
. - Call the method
PermissionsRequestHandler.handleRequest()
to start the permission request.
- Create an instance of the
- Inject the Activity to the library using the
PermissionsManager.setPermissionsActivity()
method.
Here you can see an example of an activity for requesting permissions:
public class YourRequestPermissionsActivity extends FragmentActivity {
private PermissionsRequestHandler handler;
protected void onCreate(Bundle savedInstanceState) {
// You can show a message explaining why you are going to request permissions
// and then...
handler = new PermissionsRequestHandler(this);
handler.onPermissionsResult(this::updateUI);
handler.handleRequest();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
handler.handleResult(requestCode, permissions, grantResults);
}
private void updateUI(boolean success) {
// Update your UI...
}
}
If your app runs in WearOS 4+, the POST_NOTIFICATIONS
permission will be required. To do so, we also
provide the PermissionsManager.launchRequiredPermissionsRequest()
.
Finally, here is a sample on how to setup your activity for requesting permissions:
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
// ...
// Inject the permissions Activity
PermissionsManager.setPermissionsActivity(this, YourRequestPermissionsActivity.class);
// Request Android 13+ required permissions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
PermissionsManager.launchRequiredPermissionsRequest(this);
}
}
}
The library fully handles this for you. You can start and stop the data collection from the smartphone and receive the collected data. You have to do nothing!
When starting the data collection from the smartwatch, you can chose where the collected data will be delivered: to the smartwatch itself or to the paired smartphone.
You can use the ServiceManager
provided by Background Sensors to start and stop
the data collection and receive the data in the device:
public class MainActivity extends Activity {
// ...
private CommandClient commandClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
sensorManager = new SensorManager(context);
serviceManager = new ServiceManager(this, WearSensorRecordingService.class);
}
public void setupUI() {
List<Sensor> availableSensors = sensorManager.availableSensors(WearSensor.values());
}
public void onStartSingleCommandTap(WearSensor sensor) {
CollectionConfiguration config = new CollectionConfiguration(
selectedSensor,
android.hardware.SensorManager.SENSOR_DELAY_GAME,
selectedSensor == WearSensor.HEART_RATE || selectedSensor == WearSensor.LOCATION ? 1 : 50
);
serviceManager.startCollection(config, records -> {
// ...
});
}
public void onStopSingleCommandTap(Sensor sensor) {
serviceManager.stopCollection(sensor, records -> {
// ...
});
}
// ...
}
Tip
Please, refer to the Background Sensors documentation.
To start or stop the data collection, the smartphone needs to be updated regarding the change in the data collection status. So, if we want to start/stop the data collection from the smartwatch, we have to notify that intention to the smartphone. Then, the smartphone will update its internal status and once everything is set up, it will confirm the smartwatch that the data collection can be started/stopped, so the smartwatch can act in consequence.
In order to start/stop the data collection from the smartwatch you can use the CommandClient
. Also, the sensors are defined in
WearSensor
and you can get the sensors that are available using the SensorManager
.
Here you can see a sample usage:
public class MainActivity extends Activity {
// ...
private CommandClient commandClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
commandClient = new CommandClient(this);
}
public void setupUI() {
List<Sensor> availableSensors = sensorManager.availableSensors(WearSensor.values());
}
public void onStartSingleCommandTap(Sensor sensor) {
// If the sensor requires permissions and have not been granted...
boolean requested = PermissionsManager.launchPermissionsRequestIfNeeded(this, sensor.getRequiredPermissions());
if (requested) return;
CollectionConfiguration config = new CollectionConfiguration(
selectedSensor,
android.hardware.SensorManager.SENSOR_DELAY_GAME,
selectedSensor == WearSensor.HEART_RATE || selectedSensor == WearSensor.LOCATION ? 1 : 50
);
commandClient.sendStartCommand(config);
}
public void onStopSingleCommandTap(Sensor sensor) {
commandClient.sendStopCommand(selectedSensor);
}
// ...
}
Tip
Here we are using Sensor
and CollectionConfiguration
from Background Sensors.
Check its documentation for more information.
When having a system composed by several devices (two, in our case), it is important to have a way to
communicate. We provide the PlainMessageClient
, which allows to send and receive string-based messages.
There are two types of received messages: the ones which require a response and the ones which don't.
For now, sending messages with required response is only available from the smartphone side.
Here you can see an example on how to use the messaging feature:
public class MainActivity extends Activity {
// ...
private PlainMessageClient plainMessageClient;
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
plainMessageClient = new PlainMessageClient(this);
// Register a listener for the messages
plainMessageClient.registerListener(message -> {
Log.d("MainActivity", "received " + message);
// We received a message with response required so...
if (message.responseRequired()){
Log.d("MainActivity", "response required! sending response...");
// We send a response
PlainMessage response = new PlainMessage("PONG!", message.getPlainMessage());
plainMessageClient.send(response);
}
});
}
public void onSendPlainMessageTap(View view) {
PlainMessage message = new PlainMessage("Hi! This is a test message");
plainMessageClient.send(message);
}
}
Tip
You can find a full sample of all these features in the MainActivity and RequestPermissionsActivity activities of the demo application.
Value | Description |
---|---|
ACCELEROMETER |
Represents the accelerometer sensor. |
GYROSCOPE |
Represents the gyroscope sensor. |
MAGNETOMETER |
Represents the magnetometer sensor. |
HEART_RATE |
Represents the heart rate monitor. |
LOCATION |
Represents the GPS. |
Each sensor provide the getRequiredPermissions()
method to obtain the permissions that need to be
requested for the specified sensor. Use it along PermissionsManager.launchPermissionsRequestIfNeeded()
.
Refer to the Background Sensors documentation.
Refer to the Background Sensors documentation.
Static Method | Return type | Description |
---|---|---|
setPermissionsActivity(Context context, Class<?> permissionsActivity) |
void |
Sets up the class that will be used for requesting permissions. You should call this method in your MainActivity class once your app has started. |
Method | Return type | Description |
---|---|---|
handleRequest() |
void |
Starts the workflow to request permissions. Call inside your permissions activity. |
handleResult(int requestCode, String[] permissions, int[] grantResults) |
void |
Call inside the overrided onRequestPermissionsResult of your permissions activity. |
onPermissionsResult(PermissionsResult permissionsResult) |
void |
Inject a PermissionsResult callback. The callback will be called with True if all required permissions were granted, False otherwise. |
Method | Return type | Description |
---|---|---|
sendStartCommand(CollectionConfiguration configuration) |
void |
Sends a command to the smartphone to start the collection in the smartwatch with the specified configuration. |
sendStopCommand(Sensor sensor) |
void |
Sends a command to the smartphone to stop the collection of the specified sensor in the smartwatch. |
Refer to the Background Sensors documentation.
Refer to the Background Sensors documentation.
Method | Return type | Description |
---|---|---|
registerListener(PlainMessageListener listener) |
void |
Registers the listener for the messaging feature. |
unregisterListener() |
void |
Unregisters the listener for the messaging feature. |
send(PlainMessage plainMessage) |
void |
Sends a message to the smartphone. |
Field | Type | Description |
---|---|---|
message |
String |
Content of the message. |
inResponseTo |
PlainMessage |
If the message is a response to other one, the reference to that message. null otherwise. |
Apache License 2.0
See LICENSE.
The development of this library has been possible thanks to the Spanish Ministry of Universities (grant FPU19/05352).