Skip to content

Commit

Permalink
Add docs for phone ui prompts and some improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
kul3r4 committed Feb 29, 2024
1 parent 4024874 commit e075fb3
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 116 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,8 @@ public class WearDataLayerAppHelper(

/**
* Marks that the necessary setup steps have been completed in the app such that it is ready for
* use. Typically this should be called when any pairing/login has been completed.
* use. Typically this should be called when any pairing/login has been completed. If used for
* prompting login, it should also be called during startup if login happened before
*/
public suspend fun markSetupComplete() {
surfacesInfoDataStore.updateData { info ->
Expand Down
216 changes: 112 additions & 104 deletions docs/datalayer-helpers-guide.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# DataLayer helpers libraries

These libraries provides an easy means to detect and install your app across both watch and phone.
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.
Expand All @@ -25,57 +26,64 @@ phone.
For your watch and phone projects respectively.
1. Add the capability
2. Add the capabilities
Add a `wear.xml` file in the `res/values` folder with the following content:
```xml
```
<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">
<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>
</string-array>
<!-- Used to indicate the device is a phone -->
<item>horologist_phone</item>
</string-array>
</resources>
```
On your watch and phone projects respectively.
on your wear and phone projects respectively.
For more details, see
[Specify capability names for detecting your apps](https://developer.android.com/training/wearables/apps/standalone-apps#capability-names).
1. Initialize the client, including passing a `WearDataLayerRegistry`.
3. Initialize the client including passing a `WearDataLayerRegistry`.
```kotlin
// on your watch project
val appHelper = WearDataLayerAppHelper(context, wearDataLayerRegistry, scope)
// or
// on your phone project
val appHelper = PhoneDataLayerAppHelper(context, wearDataLayerRegistry)
```
## Typical use cases:
1. **Connection and installation status**
## Connection and installation status
This is something that your app may do from time to time, or on start up.
The `DataLayerAppHelper.connectedNodes()` returns information about connected devices. You could
invoke this method at startup or while the app is running.
```kotlin
```kotlin
val connectedNodes = appHelper.connectedNodes()
```
```

The resulting list might will contain entries such as:
The resulting list might will contain entries such as:

```
```
AppHelperNodeStatus(
id=7cd1c38a,
displayName=Google Pixel Watch,
Expand Down Expand Up @@ -106,131 +114,131 @@ phone.
usage_status_value: 1
}
)
```
```

1. **Responding to availability change**
## 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.
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.

```kotlin
val nodes by appHelper.connectedAndInstalledNodes
.collectAsStateWithLifecycle()
```
```kotlin
val nodes by appHelper.connectedAndInstalledNodes
.collectAsStateWithLifecycle()
```

1. **Installing the app on the other device**
## 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:
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:

```kotlin
appHelper.installOnNode(node.id)
```
```kotlin
appHelper.installOnNode(node.id)
```

1. **Launching the app on the other device**
## Launching the app on the other device

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

```kotlin
val result = appHelper.startRemoteOwnApp(node.id)
```
```kotlin
val result = appHelper.startRemoteOwnApp(node.id)
```

1. **Launching a specific activity on the other device**
## 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:
In addition to launching your own app, you may wish to launch a different
activity as part of the user journey:

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

1. **Launching the companion app**
## Launching the companion app

In some cases, it can be useful to launch the companion app, either from the watch or the phone.
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:
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:

```kotlin
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)
}
```
```kotlin
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)
}
```

1. **Tracking Tile installation** (Wear-only)
## Tracking Tile installation (Wear-only)

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

In `onTileAddEvent`:
In `onTileAddEvent`:

```kotlin
wearAppHelper.markTileAsInstalled("SummaryTile")
```
```kotlin
wearAppHelper.markTileAsInstalled("SummaryTile")
```

In `onTileRemoveEvent`:
In `onTileRemoveEvent`:

```kotlin
wearAppHelper.markTileAsRemoved("SummaryTile")
```
```kotlin
wearAppHelper.markTileAsRemoved("SummaryTile")
```

1. **Tracking Complication installation** (Wear-only)
## Tracking Complication installation (Wear-only)

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

In `onComplicationActivated`:
In `onComplicationActivated`:

```kotlin
wearAppHelper.markComplicationAsActivated("GoalsComplication")
```
```kotlin
wearAppHelper.markComplicationAsActivated("GoalsComplication")
```

In `onComplicationDeactivated`:
In `onComplicationDeactivated`:

```kotlin
wearAppHelper.markComplicationAsDeactivated("GoalsComplication")
```
```kotlin
wearAppHelper.markComplicationAsDeactivated("GoalsComplication")
```

1. **Tracking the main activity has been launched at least once** (Wear-only)
## 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:

```kotlin
wearAppHelper.markActivityLaunchedOnce()
```
```kotlin
wearAppHelper.markActivityLaunchedOnce()
```

To check it on the phone side, use:
To check it on the phone side, use:

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

1. **Tracking the app has been set up** (Wear-only)
## 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:
To mark that the user has completed in the app the necessary setup steps such that it is ready
for use, use the following:

```kotlin
wearAppHelper.markSetupComplete()
```
```kotlin
wearAppHelper.markSetupComplete()
```

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

```kotlin
wearAppHelper.markSetupNoLongerComplete()
```
```kotlin
wearAppHelper.markSetupNoLongerComplete()
```

To check it on the phone side, use:
To check it on the phone side, use:

```kotlin
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
```
```kotlin
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
```
31 changes: 31 additions & 0 deletions docs/datalayer-phone-ui.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# DataLayer phone UI

The DataLayer phone UI library provides an implementation for phone prompts UI that can be used to
bring more users to the Wear app.

## Install app
Use the `InstallAppPrompt` to build the UI of a prompt to ask the user to install the app on their watch.

The `shouldDisplayPrompt` method allows to check if the prompt should be displayed, based on the following conditions:

- there is a watch connected

- the app is not installed

The `shouldDisplayPrompt` method is relying on the capability defined in the wear.xml of the Wear app, if the Wear app is installed
but hasn't been updated with the capability definition, this method may still return a `AppHelperNodeStatus`
indicating that the Wear app is not installed.

## ReEngage prompt
Use the `ReEngagePrompt` to build the UI of a prompt to ask the user to install the app on their watch.
The `shouldDisplayPrompt` method allows to check if the prompt should be displayed, based on
the criteria that the app is already installed.

## SignIn prompt
Use the `SignInPrompt` to build the UI of a prompt to ask the user to finish the sign in on the watch.
The `shouldDisplayPrompt` method allows to check if the prompt should be displayed, if any of the
following conditions for the `UsageStatus` is true:

- `UsageStatus.UNRECOGNIZED`
- `UsageStatus.USAGE_STATUS_UNSPECIFIED`
- `UsageStatus.USAGE_STATUS_LAUNCHED_ONCE`
18 changes: 18 additions & 0 deletions docs/datalayer-sample.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# DataLayer sample app

The goal of this sample is to show how to use the DataLayer helpers both on phone and watch.

## DataLayer phone sample app

### In-app prompts
This sample shows how to build in app prompts by using the
[Phone UI library](https://github.com/google/horologist/tree/main/datalayer/phone-ui) and the
[PhoneDataLayerAppHelper](https://github.com/google/horologist/blob/main/datalayer/phone/src/main/java/com/google/android/horologist/datalayer/phone/PhoneDataLayerAppHelper.kt).








Loading

0 comments on commit e075fb3

Please sign in to comment.