---
title: DaVinci client deep dive for Android
description: Applies to:
component: sdks
version: latest
page_id: sdks:davinci:tutorials/deep-dive-android
canonical_url: https://docs.pingidentity.com/sdks/latest/davinci/tutorials/deep-dive-android.html
revdate: Mon, 18 Nov 2024 12:13:37 +0100
keywords: ["DaVinci", "Flows", "Setup &amp; Configuration", "Source Code", "Integration"]
section_ids:
  installing_and_importing_the_davinci_client: Installing and importing the DaVinci client
  configuring_the_davinci_client: Configuring the DaVinci client
  stepping_through_davinci_flows: Stepping through DaVinci flows
  starting_a_davinci_flow: Starting a DaVinci flow
  determining_davinci_flow_node_type: Determining DaVinci flow node type
  continue_node_type_android: Handling DaVinci flow collectors in continue nodes
  continuing_a_davinci_flow: Continuing a DaVinci flow
  error_node_type_android: Handling DaVinci flow error nodes
  failure_node_type_android: Handling DaVinci flow failure nodes
  success_node_type_android: Handling DaVinci flow success nodes
  leverage_jetpack_compose: Leverage Jetpack Compose
---

# DaVinci client deep dive for Android

***Applies to***:

* [icon: check-square-o, set=fa]DaVinci client for Android

* [icon: square-o, set=fa]DaVinci client for iOS

* [icon: square-o, set=fa]DaVinci client for JavaScript

Configure DaVinci client for Android properties to connect to PingOne and step through an associated DaVinci flow.

## Installing and importing the DaVinci client

To use the DaVinci client for Android, add the relevant dependencies to your project:

1. In the **Project** tree view of your Android Studio project, open the `Gradle Scripts/build.gradle.kts` file for the DaVinci *module*.

2. In the `dependencies` section, add the following:

   ```gradle
   implementation("com.pingidentity.sdks:davinci:1.3.0")
   ```

   Example of the `dependencies` section after editing:

   ```gradle
   dependencies {

       val composeBom = platform(libs.androidx.compose.bom)
       implementation(composeBom)

       // DaVinci client
       implementation("com.pingidentity.sdks:davinci:1.3.0")

       ...

       implementation(libs.androidx.core.ktx)
       implementation(libs.androidx.appcompat)
       implementation(libs.material)
   }
   ```

## Configuring the DaVinci client

Configure DaVinci client for Android properties to connect to PingOne and step through an associated DaVinci flow.

The following shows an example DaVinci client configuration, using the underlying `Oidc` module:

Configure DaVinci client connection properties

```kotlin
import com.pingidentity.davinci.DaVinci
import com.pingidentity.davinci.module.Oidc

val daVinci = DaVinci {
    module(Oidc) {
        clientId = "6c7eb89a-66e9-ab12-cd34-eeaf795650b2"
        discoveryEndpoint = "https://auth.pingone.com/3072206d-c6ce-ch15-m0nd-f87e972c7cc3/" +
            "as/.well-known/openid-configuration"
        scopes = mutableSetOf("openid", "profile", "email", "address", "revoke")
        redirectUri = "org.forgerock.demo://oauth2redirect"
        additionalParameters = mapOf("customKey" to "customValue")
    }
}
```

For information on the properties available, refer to [Configure DaVinci client for Android properties](../sdkconfiguration/configure-sdk-android.html).

## Stepping through DaVinci flows

To authenticate your users the DaVinci client for Android must start the flow, and step through each node.

|   |                                                                                                                              |
| - | ---------------------------------------------------------------------------------------------------------------------------- |
|   | For information on which connectors and fields the DaVinci client supports, refer to [Compatibility](../compatibility.html). |

### Starting a DaVinci flow

To start a DaVinci flow, call the `start()` method:

Start a DaVinci flow

```kotlin
val node = daVinci.start()
```

### Determining DaVinci flow node type

Each step of the flow returns one of four node types:

* `ContinueNode`

  This type indicates there is input required from the client. The `node` object for this type contains a `collector` object, which describes the information it requires from the client.

  Learn more in [Handling DaVinci flow collectors in continue nodes](#continue_node_type_android).

* `SuccessNode`

  This type indicates the flow is complete, and authentication was successful.

  Learn more in [Handling DaVinci flow success nodes](#success_node_type_android).

* `ErrorNode`

  This type indicates an error in the data sent to the server. For example, an email address in an incorrect format, or a password that does not meet complexity requirements.

  You can correct the error and resubmit to continue the flow.

  Learn more in [Handling DaVinci flow error nodes](#error_node_type_android).

* `FailureNode`

  This type indicates that the flow could not be completed and must be restarted. This can be caused by a server error, or a timeout.

  Learn more in [Handling DaVinci flow failure nodes](#failure_node_type_android).

You can use the helper functions to determine which node type the server has returned:

Determine `node` type.

```kotlin
when (node) {
    is ContinueNode -> {}
    is ErrorNode -> {}
    is FailureNode -> {}
    is SuccessNode -> {}
}
```

### Handling DaVinci flow collectors in continue nodes

The `ContinueNode` type contains `collectors`. These collectors define what information or action to request from the user, or client device.

|   |                                                                                                                                                          |
| - | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | For a list of supported collectors, refer to [Supported PingOne fields and collectors](../../release-notes/compatibility.html#supported-davinci-fields). |

There are specific collector types. For example there are `TextCollector` and `PasswordCollector` types.

To complete a DaVinci flow we recommend that you implement a component for each connector type you will encounter in the flow. Then you can iterate through the flow and handle each collector as you encounter it.

Access collectors in a `ContinueNode`

```kotlin
node.collectors.forEach {
    when(it) {
        is TextCollector → it.value = "My First Name"
        is PasswordCollector → it.value = "My Password"
        is SubmitCollector → it.value = "click me"
        is FlowCollector → it.value = "Forgot Password"
    }
}
```

### Continuing a DaVinci flow

After collecting the data for a node you can proceed to the next node in the flow by calling the `next()` method on your current `node` object.

Continue a DaVinci flow using `next()`

```kotlin
val next = node.next()
```

|   |                                                                                                                                                                  |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | You do not need to pass any parameters into the `next` method as the DaVinci client internally stores the updated object, ready to return to the PingOne server. |

The server responds with a new `node` object, just like when starting a flow initially.

Loop again through conditional checks on the new node's type to render the appropriate UI or take the appropriate action.

### Handling DaVinci flow error nodes

DaVinci flows return the `ErrorNode` type when it receives data that is incorrect, but you can fix the data and resubmit. For example, an email value submitted in an invalid format or a new password that is too short.

You can retrieve the error message by using `node.message()`, and the raw JSON response with `node.input`.

Displaying the reason for an error

```kotlin
val node = daVinci.start() // Start the flow

//Determine the Node Type
when (node) {
    is ContinueNode -> {}
    is ErrorNode -> {
        node.message() // Retrieve the cause of the error
    }
    is FailureNode -> {}
    is SuccessNode -> {}
}
```

|   |                                                                                                          |
| - | -------------------------------------------------------------------------------------------------------- |
|   | This is different than a `FailureNode` type, which you cannot resubmit and must restart the entire flow. |

You can retain a reference to the `node` you submit in case the next `node` you receive is an `ErrorNode` type. If so, you can re-render the previous form, and inject the error information from the new `ErrorNode` node.

After the user revises the data call `next()` as you did before.

### Handling DaVinci flow failure nodes

DaVinci flows return the `FailureNode` type if there has been an issue that prevents the flow from continuing. For example, the flow times out or suffers a server error.

You can retrieve the cause of the failure by using `node.cause()`, which is a `Throwable` object.

Handling receipt of a `FailureNode` type

```kotlin
val node = daVinci.start() // Start the flow

//Determine the Node Type
when (node) {
    is ContinueNode -> {}
    is ErrorNode -> {}
    is FailureNode -> {
        node.cause() // Retrieve the error message
    }
    is SuccessNode -> {}
}
```

You should offer to restart the flow on receipt of a `FailureNode` type.

### Handling DaVinci flow success nodes

DaVinci flows return the `SuccessNode` type when the user completes the flow and PingOne issues them a session.

To retrieve the existing session, you can use the following code:

Handling receipt of a `SuccessNode` type

```kotlin
val user: User? = daVinci.user()

user?.let {
    it.accessToken()
    it.revoke()
    it.userinfo()
    it.logout()
}
```

## Leverage Jetpack Compose

The following shows how you could use the DaVinci client with Jetpack Compose:

ViewModel

```kotlin
// Define State that listen by the View
var state = MutableStateFlow<Node>(Empty)

//Start the DaVinci flow
val next = daVinci.start()

// Update the state
state.update {
    next
}

fun next(node: ContinueNode) {
    viewModelScope.launch {
        val next = node.next()
        state.update {
            next
        }
    }
}
```

View

```kotlin
when (val node = state.node) {
    is ContinueNode -> {}
    is ErrorNode -> {}
    is FailureNode -> {}
    is SuccessNode -> {}
}
```
