RemoteActivityHelper


public final class RemoteActivityHelper


Support for opening android intents on other devices.

The following example opens play store for the given app on another device:

val remoteActivityHelper = RemoteActivityHelper(context, executor)

val result = remoteActivityHelper.startRemoteActivity(
Intent(Intent.ACTION_VIEW)
.setData(
Uri.parse("http://play.google.com/store/apps/details?id=com.example.myapp"))
.addCategory(Intent.CATEGORY_BROWSABLE),
nodeId)

startRemoteActivity returns a ListenableFuture, which is completed after the intent has been sent or failed if there was an issue with sending the intent.

nodeId is the opaque string that represents a node in the Android Wear network. For the given device, it can obtained by NodeClient.getLocalNode() and the list of nodes to which this device is currently connected can be obtained by NodeClient.getConnectedNodes(). More information about this can be found here.

Summary

Nested types

Constants

static final @NonNull String
static final @NonNull String

Permission required to use startPhoneActivityWithUnlock.

static final int

Result code passed to ResultReceiver.send when a remote intent failed to send.

static final int

Result code passed to ResultReceiver.send when a remote intent was sent successfully.

static final int

Indicates that remote activity is available.

static final int

Indicates that remote activity is temporarily unavailable.

static final int

The remote auth's availability is unknown.

static final int

The remote activity's availability is unknown.

Public constructors

Public methods

final @NonNull Flow<@NonNull Integer>

Status of whether RemoteActivityHelper can startRemoteActivity, if known.

static final Intent

Returns the android.content.Intent extra specifying remote intent.

static final String

Returns the String extra specifying node ID of remote intent.

final @NonNull ListenableFuture<@NonNull Void>
@RequiresApi(value = 37)
@RequiresPermission(value = "com.google.wear.permission.SEND_CONTINUE_ACTIVITY_ON_PHONE")
startPhoneActivityWithUnlock(
    @NonNull String callerPackage,
    @NonNull String targetPackage,
    @NonNull String targetAction,
    @NonNull Uri targetUri,
    @NonNull List<@NonNull String> targetCategories
)

Starts an activity on the companion phone device, requesting a remote unlock.

final @NonNull ListenableFuture<@NonNull Void>
startRemoteActivity(@NonNull Intent targetIntent, String targetNodeId)

Start an activity on another device.

final @NonNull ListenableFuture<@NonNull Void>
startRemoteActivityAttemptUnlock(
    @NonNull Uri targetUri,
    @NonNull List<@NonNull String> targetCategories
)

Starts an activity on the companion phone device, requesting a remote unlock if supported and PERMISSION_SEND_CONTINUE_ACTIVITY_ON_PHONE is granted.

Constants

ACTION_REMOTE_INTENT

public static final @NonNull String ACTION_REMOTE_INTENT

PERMISSION_SEND_CONTINUE_ACTIVITY_ON_PHONE

public static final @NonNull String PERMISSION_SEND_CONTINUE_ACTIVITY_ON_PHONE

Permission required to use startPhoneActivityWithUnlock.

RESULT_FAILED

public static final int RESULT_FAILED = 1

Result code passed to ResultReceiver.send when a remote intent failed to send.

RESULT_OK

public static final int RESULT_OK = 0

Result code passed to ResultReceiver.send when a remote intent was sent successfully.

STATUS_AVAILABLE

public static final int STATUS_AVAILABLE = 3

Indicates that remote activity is available.

There is a connected device capable to handle the remote interaction.

STATUS_TEMPORARILY_UNAVAILABLE

public static final int STATUS_TEMPORARILY_UNAVAILABLE = 2

Indicates that remote activity is temporarily unavailable.

There is a known paired device, but it is not currently connected or reachable to handle the remote interaction.

STATUS_UNAVAILABLE

public static final int STATUS_UNAVAILABLE = 1

The remote auth's availability is unknown.

On older devices, STATUS_UNKNOWN is returned as we can not determine the availability states. To preserve compatibility with existing devices behavior, try startRemoteActivity and handle error codes accordingly.

STATUS_UNKNOWN

public static final int STATUS_UNKNOWN = 0

The remote activity's availability is unknown.

Public constructors

RemoteActivityHelper

Added in 1.0.0
public RemoteActivityHelper(@NonNull Context context, @NonNull Executor executor)
Parameters
@NonNull Context context

The Context of the application for sending the intent.

@NonNull Executor executor

Executor used for getting data to be passed in remote intent. If not specified, default will be Executors.newSingleThreadExecutor().

Public methods

getAvailabilityStatus

Added in 1.1.0
public final @NonNull Flow<@NonNull IntegergetAvailabilityStatus()

Status of whether RemoteActivityHelper can startRemoteActivity, if known.

In scenarios of restricted connection or temporary disconnection with a paired device, startRemoteActivity will not be available. Please check availabilityStatus before calling startRemoteActivity to provide better experience for the user.

Wear devices start to support determining the availability status from Wear Sdk WEAR_TIRAMISU_4. On older wear devices, it will always return STATUS_UNKNOWN. On phone devices, it will always return STATUS_UNKNOWN.

import androidx.wear.remote.interactions.RemoteActivityHelper

remoteActivityHelper.availabilityStatus.collect { status ->
    when (status) {
        RemoteActivityHelper.STATUS_UNAVAILABLE ->
            TODO("Hide or present alternative flow as remote flow is not available.")
        RemoteActivityHelper.STATUS_TEMPORARILY_UNAVAILABLE ->
            TODO("Present education to user to connect devices or bring to proximity.")
        RemoteActivityHelper.STATUS_AVAILABLE,
        RemoteActivityHelper.STATUS_UNKNOWN ->
            // Present normal remote device flow when we don't know (old devices)
            // or when we know it is available.
            remoteActivityHelper.startRemoteActivity(remoteIntent)
    }
}
Returns
@NonNull Flow<@NonNull Integer>

a Flow with a stream of status updates that could be one of STATUS_UNKNOWN, STATUS_UNAVAILABLE, STATUS_TEMPORARILY_UNAVAILABLE, STATUS_AVAILABLE.

getTargetIntent

Added in 1.0.0
public static final Intent getTargetIntent(@NonNull Intent intent)

Returns the android.content.Intent extra specifying remote intent.

Parameters
@NonNull Intent intent

The intent holding configuration.

Returns
Intent

The remote intent, or null if none was set.

getTargetNodeId

Added in 1.0.0
public static final String getTargetNodeId(@NonNull Intent intent)

Returns the String extra specifying node ID of remote intent.

Parameters
@NonNull Intent intent

The intent holding configuration.

Returns
String

The node id, or null if none was set.

startPhoneActivityWithUnlock

Added in 1.3.0-alpha01
@RequiresApi(value = 37)
@RequiresPermission(value = "com.google.wear.permission.SEND_CONTINUE_ACTIVITY_ON_PHONE")
public final @NonNull ListenableFuture<@NonNull VoidstartPhoneActivityWithUnlock(
    @NonNull String callerPackage,
    @NonNull String targetPackage,
    @NonNull String targetAction,
    @NonNull Uri targetUri,
    @NonNull List<@NonNull String> targetCategories
)

Starts an activity on the companion phone device, requesting a remote unlock.

This API requests to start an activity on the companion phone. If the phone is locked, it may also request to initiate unlocking the phone before launching the target application if below system conditions allow it.

This API is only available on API 37 and above.

To use this function, the following conditions must be met:

  • Note that this method only works when it's called from the watch.

  • The calling application must be granted PERMISSION_SEND_CONTINUE_ACTIVITY_ON_PHONE.

  • The targetPackage must be the same package (or a trusted peer application) on the connected phone, and its SHA1 certificate fingerprint must match the source package on the watch. The callerPackage must also accurately match the calling app's package name.

  • The caller application must be running in the foreground when the request is made.

  • The request must be the direct result of an explicit user interaction (for example, tapping a "show on phone" button).

  • User should have enrolled in the feature.

  • An active authentication session must exist between the devices. This requires both devices support the feature, the watch is currently unlocked and near the phone while they are connected via Bluetooth, and the phone has been unlocked by the user at least once after the watch was unlocked and placed on the user's body.

There are no restrictions on targetAction, targetUri or targetCategories as long as they are not empty.

Use this method to launch explicitly targeted intents (specifying target package, action, URI, and categories) instead of public browsable links, and if your flow strictly requires an unlocked phone without automatic fallbacks.

Exception Conditions:

Parameters
@NonNull String callerPackage

The package name of the calling app. This is required.

@NonNull String targetPackage

The package name of the activity to start on the phone. This is required.

@NonNull String targetAction

The action of the activity to start on the phone. This is required.

@NonNull Uri targetUri

The data URI of the activity to start on the phone. This is required and cannot be empty.

@NonNull List<@NonNull String> targetCategories

The categories of the activity to start on the phone. This is required.

Returns
@NonNull ListenableFuture<@NonNull Void>

A ListenableFuture which resolves if the request was successfully sent, or throws an Exception if the request failed or the parameters were invalid. If there's a problem with starting remote activity, RemoteIntentException will be thrown.

Throws
IllegalStateException

If PERMISSION_SEND_CONTINUE_ACTIVITY_ON_PHONE has not been granted.

IllegalArgumentException

If any of the required parameters are empty.

UnsupportedOperationException

If this remote unlock API is unsupported on this device.

startRemoteActivity

Added in 1.0.0
public final @NonNull ListenableFuture<@NonNull VoidstartRemoteActivity(@NonNull Intent targetIntent, String targetNodeId)

Start an activity on another device.

This API currently supports sending intents with action set to android.content.Intent.ACTION_VIEW, a data URI populated using android.content.Intent.setData, and with the category android.content.Intent.CATEGORY_BROWSABLE present.

When targetNodeId is unspecified, if the current device is a watch, the activity will start on the companion phone device. Otherwise, the activity will start on all connected watch devices.

If the intent passed in sets a different action or does not contain the CATEGORY_BROWSABLE category or does not set a data URI, the call will be rejected and a kotlin.IllegalArgumentException thrown.

Besides the mandated action and category, the caller must provide a data URI and an optional set of categories to be delivered to the remote device.

If any additional attributes of the intent are set (for examples, extras, package, component), they will be stripped from the intent. Only an intent with ACTION_VIEW, CATEGORY_BROWSABLE, any other specified categories, and the provided data URI will be delivered to the remote devices.

From Wear 6, the Wear SDK on the Watch will be used for starting remote activities on the connected companion.

Parameters
@NonNull Intent targetIntent

The intent to open on the remote device. Action must be set to android.content.Intent.ACTION_VIEW, a data URI must be populated using android.content.Intent.setData, and the category android.content.Intent.CATEGORY_BROWSABLE must be present.

String targetNodeId

Wear OS node id for the device where the activity should be started. If null, and the current device is a watch, the activity will start on the companion phone device. Otherwise, the activity will start on all connected watch devices.

Returns
@NonNull ListenableFuture<@NonNull Void>

The ListenableFuture which resolves if starting activity was successful or throws Exception if any errors happens. If there's a problem with starting remote activity, RemoteIntentException will be thrown.

startRemoteActivityAttemptUnlock

Added in 1.3.0-alpha01
public final @NonNull ListenableFuture<@NonNull VoidstartRemoteActivityAttemptUnlock(
    @NonNull Uri targetUri,
    @NonNull List<@NonNull String> targetCategories
)

Starts an activity on the companion phone device, requesting a remote unlock if supported and PERMISSION_SEND_CONTINUE_ACTIVITY_ON_PHONE is granted.

The remote unlock aspect of the request is subject to a strict set of security conditions:

  • The remote unlock part is only applicable when the request is initiated from a Wear OS watch.

  • The calling application must be granted PERMISSION_SEND_CONTINUE_ACTIVITY_ON_PHONE.

  • The app must be in the foreground.

  • The request must be the result of explicit user interaction.

  • User should have enrolled in the feature.

  • An active authentication session must exist between the devices. This requires both devices support the feature, the watch is currently unlocked and near the phone while they are connected via Bluetooth, and the phone has been unlocked by the user at least once after the watch was unlocked and placed on the user's body.

To initiate the launch, this method will generate an intent with an android.content.Intent.ACTION_VIEW action, the provided targetUri, and the caller's targetCategories (which must include android.content.Intent.CATEGORY_BROWSABLE category).

If remote unlock is not supported or conditions are not met (for example, missing permission, or if the authentication session ends), this method falls back to startRemoteActivity behavior. In this case, no remote unlock will be requested and the user will have to manually unlock their phone if it is locked before activity is launched.

Use this method for broad compatibility on watches, providing an easy upgrade path for existing users of startRemoteActivity. On API 37 and above, this method attempts unlocking the phone, automatically falling back to a standard remote launch if unavailable. On API below 37, it functions as a standard remote launch. Intents must match the listed limitations.

Parameters
@NonNull Uri targetUri

The data URI of the activity to start on the phone. This must not be empty.

@NonNull List<@NonNull String> targetCategories

The categories of the activity to start on the phone. This must contain android.content.Intent.CATEGORY_BROWSABLE. If not specified, by default it will be android.content.Intent.CATEGORY_BROWSABLE.

Returns
@NonNull ListenableFuture<@NonNull Void>

A ListenableFuture which resolves if the request was successfully sent, or throws an Exception if the request failed or the parameters were invalid.