# Android client SDK

The Sending.Network Android SDK provides a messaging framework that enables you to integrate chatroom and notification services within your mobile applications. \
\
This quickstart will walk you through a simple demo that makes basic API calls like user registration, room creation, etc. Please refer to the SDK demo for the completed code.

## Prerequisites <a href="#prerequisites" id="prerequisites"></a>

| Components | Requirements                                                                                                                                              |
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| OS         | Android 6.0 or above                                                                                                                                      |
| Software   | <ul><li>Android Studio 4.0 or above</li><li><a href="https://github.com/Sending-Network/sendingnetwork-android">Sending.Network Android SDK</a></li></ul> |

## Configure your build

### Gradle

Add the following code to the top-level _build.gradle_ configuration file:

```groovy
buildscript {
    ext.kotlin_version = "1.6.0"
    repositories {
        google()
        jcenter()
        maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
    }
    dependencies {
        classpath "com.android.tools.build:gradle:7.0.3"
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}
```

Add the `sendingnetwork-android-sdk` dependency in app module _build.gradle_ file. Replace the `x.y.z` with the SDK version number.

<pre class="language-groovy"><code class="lang-groovy"><strong>// SDK dependency
</strong>implementation 'io.github.sending-network:sendingnetwork-android-sdk:x.y.z'
</code></pre>

If you intend to run a local P2P node, add the `sendingnetwork-android-service` as well. Replace the `x.y.z` with the SDK version number.

```groovy
// P2P node dependency
implementation 'io.github.sending-network:sendingnetwork-android-service:x.y.z'
```

### AndroidManifest.xml file

Your application should at least contain the provider `InitializationProvider` to remove the initialization of the `WorkManager` as below:

```xml
<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:name=".SampleApp"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        [...]

        // This is required as the WorkManager is already initialized by the SDK
        <provider
            android:name="androidx.startup.InitializationProvider"
            android:authorities="${applicationId}.androidx-startup"
            android:exported="false"
            tools:ignore="MissingClass"
            tools:node="merge">
            <meta-data
                android:name="androidx.work.WorkManagerInitializer"
                android:value="androidx.startup"
                tools:node="remove" />
        </provider>
    
        // Declare the RadixService only when running a local P2P node
        <service android:name="org.sdn.android.sdk.server.RadixService"
                 android:enabled="true"/>

    </application>
```

## Initialization and DID login

### Application initialization

Create `SDNClient` instance from the `onCreate()` method of the child class of `Application`.

```kotlin
    override fun onCreate() {
        super.onCreate()
        Timber.plant(Timber.DebugTree())
        // Initialize the Client instance
        client = Client(
            context = this,
            clientConfiguration = ClientConfiguration(
                roomDisplayNameFallbackProvider = RoomDisplayNameFallbackProviderImpl()
            )
        )
        // If there has been a session then starts syncing messages.
        // Otherwise complete the login process on the login page.
        val lastSession = client.authenticationService().getLastAuthenticatedSession()
        if (lastSession != null) {
            SessionHolder.currentSession = lastSession
            lastSession.open()
            lastSession.syncService().startSync(true)
        }
    }
```

### Network configuration

There are two ways to join the SDN network. You can create a local P2P service to communicate with the SDN network. Or, you may connect to an existing Edge Node and enjoy the P2P messaging.

* To connect to a remote Edge Node:

{% hint style="info" %}
Please contact developer@sending.network for a test server URL and set it as the `nodeUrl`.
{% endhint %}

```kotlin
// Connect to a remote Edge Node
val nodeUrl = "https://node-domain"
val nodeConnectionConfig = nodeConnectionConfig.Builder()
                .withNodeUri(Uri.parse(node))
                .build()
```

* To run a local P2P node:

```kotlin
// Start the node service
val intent = Intent(context, RadixService::class.java)
context.startService(intent)

// Connect to local P2P service
val nodeUrl = "http://localhost:65432"
val nodeConnectionConfig = NodeConnectionConfig.Builder()
                .withNodeUri(Uri.parse(node))
                .build()
```

### DID login

You will need a developer key to access the Edge Network. To request and utilize a developer key, please refer to the guide provided [here](developer-key).

The client calls the login-related APIs through `AuthenticationService`:

1. Query for existing DIDs associated with current wallet address.
2. Obtain login message by using one of the DIDs or the wallet address if no DID exists.
3. Request for a message signature with the developer key.
4. Request for a message signature with the user's wallet account.
5. Login by passing the two signatures to the edge node.

```kotlin
val address = ""
val privateKey = ""
val ecKeyPair: ECKeyPair = ECKeyPair.create(privateKey.decodeHex().toByteArray())
val authService = SampleApp.getSDNClient(requireContext()).authenticationService()
try {
    val loginDidMsg = authService.didPreLogin(edgeNodeConnectionConfig, address)
    // sign with user wallet
    val token = signMessage(ecKeyPair, loginDidMsg.message)
    // sign with developer key from server side
    val appToken = signWithServerDeveloperKey((loginDidMsg.message))
    authService.didLogin(edgeNodeConnectionConfig, address,
        loginDidMsg.did, loginDidMsg.randomServer, loginDidMsg.updated, token, appToken)
} catch (failure: Throwable) {
    Toast.makeText(requireContext(), "Failure: $failure", Toast.LENGTH_SHORT).show()
    null
}?.let {
    SessionHolder.currentSession = it
    it.open()
    it.syncService().startSync(true)
    displayRoomList()
}
```

Your developer key server needs to perform the signing operation. Below is an example code for the client to request a signature from the server:"

```kotlin
suspend fun signWithServerDeveloperKey(message: String): String {
        val retrofit: Retrofit = Retrofit.Builder()
            .baseUrl("https://rewards.sending.network")
            .addConverterFactory(MoshiConverterFactory.create(Moshi.Builder().add(KotlinJsonAdapterFactory()).build()))
            .client(OkHttpClient())
            .build()
        val signService = retrofit.create(SignService::class.java)
        val signResp = signService.signMessage(SignRequest(message))
        return signResp.signature
    }
```

### Create a private chat

Invite a user to a private chat room with the user id.

```kotlin
val session = SessionHolder.currentSession
val otherUserId = "@sdn_0829932f18b936f9c878bf1332b53214c11380cb:0829932f18b936f9c878bf1332b53214c11380cb"
// Create a private chat room
val roomId = session.roomService().createDirectRoom(otherUserId)
val room? = session.getRoom(roomId)
// Display the room information
room?.getRoomSummaryLive()?.observe(viewLifecycleOwner) { roomSummary ->
    // display room summary on application UI
}
```

### Send and receive messages

```kotlin
// Send a message
room?.sendService()?.sendTextMessage("Hello!")

// Set timeline listener
val timelineSettings = TimelineSettings(initialSize = 30)
val timeline = room?.timelineService()?.createTimeline(null, timelineSettings)?.also {
    it.addListener(this)
    it.start()
}

// set callback function in the listener
override fun onTimelineUpdated(snapshot: List<TimelineEvent>) {
    // call this method to process the timeline event
    // when there's an update in timeline
}
```

### Initiating Video Conference

Open a video conference by using the room ID.
