Skip to content

DataLayer helpers libraries

The DataLayer helpers libraries help tracking the connection between phone and watch and start flows from the such as installing the app

However, they are not intended to cover complex use cases, or complex interactions between watch and phone.

Getting started

  1. Include the necessary dependency:
dependencies {
    implementation "com.google.android.horologist:horologist-datalayer-watch:<version>"
}

and

dependencies {
    implementation "com.google.android.horologist:horologist-datalayer-phone:<version>"
}

For your watch and phone projects respectively.

  1. Add the capabilities

Add a wear.xml file in the res/values folder with the following content:

```
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@array/android_wear_capabilities">
    <string-array name="android_wear_capabilities">
        <!-- Used to indicate that the app is installed on this device -->
        <item>data_layer_app_helper_device_watch</item>
        <!-- Used to indicate the device is a watch -->
        <item>horologist_watch</item>
    </string-array>
</resources>
```

and

```xml
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:keep="@array/android_wear_capabilities">
    <string-array name="android_wear_capabilities" translatable="false" tools:ignore="UnusedResources">
        <!-- Used to indicate that the app is installed on this device -->
        <item>data_layer_app_helper_device_phone</item>
        <!-- Used to indicate the device is a phone -->
        <item>horologist_phone</item>
</string-array>
</resources>
```

on your wear and phone projects respectively.

For more details, see Specify capability names for detecting your apps.

  1. Initialize the client including passing a WearDataLayerRegistry.

    // on your watch project
    val appHelper = WearDataLayerAppHelper(context, wearDataLayerRegistry, scope)
    
    // on your phone project
    val appHelper = PhoneDataLayerAppHelper(context, wearDataLayerRegistry)
    

Check API availability

This API relies on Google Play services to be available and up-to-date on the device. You can check the availability with:

if (!phoneDataLayerAppHelper.isAvailable()) {
    // display error 
}

Please refer to GoogleApiAvailability if you would like to display an UI to request the user to install or update Google Play.

Connection and installation status

The DataLayerAppHelper.connectedNodes() returns information about connected devices. You could invoke this method at startup or while the app is running.

val connectedNodes = appHelper.connectedNodes()

The resulting list might will contain entries such as:

 AppHelperNodeStatus(
     id=7cd1c38a,
     displayName=Google Pixel Watch,
     appInstallationStatus=Installed(nodeType=WATCH),
     surfacesInfo=# SurfacesInfo@125fcbff
         complications {
             instance_id: 1234
             name: "MyComplication"
             timestamp {
                 nanos: 738000000
                 seconds: 1680015523
             }
             type: "SHORT_TEXT"
         }
         tiles {
             name: "MyTile"
             timestamp {
                 nanos: 364000000
                 seconds: 1680016845
             }
         }
         usage_info {
             timestamp {
                 nanos: 669000000
                 seconds: 1701708501
             }
             usage_status: USAGE_STATUS_LAUNCHED_ONCE
             usage_status_value: 1
         }
 )

Responding to availability change

Once you've established the app on both devices, you may wish to respond to when the partner device connects or disconnects. For example, you may only want to show a "launch workout" button on the phone when the watch is connected.

val nodes by appHelper.connectedAndInstalledNodes
    .collectAsStateWithLifecycle()

Installing the app on the other device

Where the app isn't installed on the other device - be that phone or watch - then the library offers a one step option to launch installation:

appHelper.installOnNode(node.id)

Launching the app on the other device

If the app is installed on the other device, you can launch it remotely:

val result = appHelper.startRemoteOwnApp(node.id)

Launching a specific activity on the other device

In addition to launching your own app, you may wish to launch a different activity as part of the user journey:

val config = activityConfig {
    classFullName = "com.example.myapp.MyActivity"
}
appHelper.startRemoteActivity(node.id, config)

Launching the companion app

In some cases, it can be useful to launch the companion app, either from the watch or the phone.

For example, if the connected device does not have your Tile installed, you may wish to offer the user the option to navigate to the companion app to install it:

if (node.surfacesInfo.tilesList.isEmpty() && askUserAttempts < MAX_ATTEMPTS) {
    // Show guidance to the user and then launch companion
    // to allow the to install the Tile.
    val result = appHelper.startCompanion(node.id)
}

Tracking Tile installation (Wear-only)

To determine whether your Tile(s) are installed, add the following to your TileService:

In onTileAddEvent:

wearAppHelper.markTileAsInstalled("SummaryTile")

In onTileRemoveEvent:

wearAppHelper.markTileAsRemoved("SummaryTile")

If you want to open the Tile Settings editor on your phone, you can use phoneDataLayerAppHelper.checkCompanionVersionSupportTileEditing to check that the Companion version supports deeplink into Tiles Settings editor and phoneDataLayerAppHelper.findWatchToInstallTile to check if there is a connected watch where the Tile can be installed.

Tracking Complication installation (Wear-only)

To determine whether your Complication(s) are in-use, add the following to your ComplicationDataSourceService:

In onComplicationActivated:

wearAppHelper.markComplicationAsActivated("GoalsComplication")

In onComplicationDeactivated:

wearAppHelper.markComplicationAsDeactivated("GoalsComplication")

Tracking the main activity has been launched at least once (Wear-only)

To mark that your main activity on the watch app has been launched once, use:

wearAppHelper.markActivityLaunchedOnce()

To check it on the phone side, use:

val connectedNodes = appHelper.connectedNodes()
// after picking a node, check if value is USAGE_STATUS_LAUNCHED_ONCE
node.surfacesInfo.usageInfo.usageStatus

Tracking the app has been set up (Wear-only)

To mark that the user has completed in the app the necessary setup steps such that it is ready for use, use the following:

wearAppHelper.markSetupComplete()

And when the app is no longer considered in a fully setup state, use the following:

wearAppHelper.markSetupNoLongerComplete()

To check it on the phone side, use:

val connectedNodes = appHelper.connectedNodes()
// after picking a node, check if value is either USAGE_STATUS_LAUNCHED_ONCE
// or USAGE_STATUS_SETUP_COMPLETE
node.surfacesInfo.usageInfo.usageStatus