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.2.0'
}
The library has the following requirements:
[!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:
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:
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:
PermissionsManager.launchPermissionsRequestIfNeeded()
method.PermissionsRequestHandler
class.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.Activity.onRequestPermissionsResult
and inside it, call PermissionsRequestHandler.handleResult()
.PermissionsRequestHandler.handleRequest()
to start the permission request.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
andCollectionConfiguration
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.
WearSensor
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()
.
SensorManager
Refer to the Background Sensors documentation.
ServiceManager
Refer to the Background Sensors documentation.
PermissionsManager
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. |
PermissionsRequestHandler
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. |
CommandClient
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.
PlainMessageClient
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. |
PlainMessage
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).