|
| 1 | +--- |
| 2 | +author: dhiraj |
| 3 | +ms.author: dhiraj |
| 4 | +ms.date: 11/29/2022 |
| 5 | +ms.topic: include |
| 6 | +ms.service: azure-communication-services |
| 7 | +--- |
| 8 | + |
| 9 | +Get the sample Android application for this [quickstart](https://github.com/Azure-Samples/communication-services-android-quickstarts/tree/main/ui-library-quick-start) in the open source Azure Communication Services [UI Library for Android](https://github.com/Azure/communication-ui-library-android). |
| 10 | + |
| 11 | +## Prerequisites |
| 12 | + |
| 13 | +- An Azure account and an active Azure subscription. [Create an account for free](https://azure.microsoft.com/free/?WT.mc_id=A261C142F). |
| 14 | +- An OS running [Android Studio](https://developer.android.com/studio). |
| 15 | +- A deployed [Azure Communication Services resource](../../../create-communication-resource.md), note the endpoint URL. |
| 16 | +- An Azure Communication Services [access token](../../../identity/quick-create-identity.md) and user identifier. |
| 17 | +- An Azure Communication Services [chat thread](../../../chat/get-started.md) with above user added to it. |
| 18 | + |
| 19 | + |
| 20 | +## Set up the project |
| 21 | + |
| 22 | +Complete the following sections to set up the quickstart project. |
| 23 | + |
| 24 | +### Create a new Android project |
| 25 | + |
| 26 | +In Android Studio, create a new project: |
| 27 | + |
| 28 | +1. In the **File** menu, select **New** > **New Project**. |
| 29 | + |
| 30 | +1. In **New Project**, select the **Empty Activity** project template. |
| 31 | + |
| 32 | + :::image type="content" source="../../media/composite-android-new-project.png" alt-text="Screenshot that shows the New Project dialog in Android Studio with Empty Activity selected."::: |
| 33 | + |
| 34 | +1. Select **Next**. |
| 35 | + |
| 36 | +1. In **Empty Activity**, name the project **UILibraryQuickStart**. For language, select **Java/Kotlin**. For the minimum SDK, select **API 23: Android 6.0 (Marshmallow)** or later. |
| 37 | + |
| 38 | +1. Select **Finish**. |
| 39 | + |
| 40 | + :::image type="content" source="../../media/chat-android-new-project.png" alt-text="Screenshot that shows new project options and the Finish button selected."::: |
| 41 | + |
| 42 | +## Install the packages |
| 43 | + |
| 44 | +Complete the following sections to install the required application packages. |
| 45 | + |
| 46 | +### Add a dependency |
| 47 | + |
| 48 | +In your app-level *UILibraryQuickStart/app/build.gradle* file (in the app folder), add the following dependency: |
| 49 | + |
| 50 | +```groovy |
| 51 | +dependencies { |
| 52 | + ... |
| 53 | + implementation 'com.azure.android:azure-communication-ui-chat:+' |
| 54 | + ... |
| 55 | +} |
| 56 | +``` |
| 57 | + |
| 58 | +### Add Maven repositories |
| 59 | + |
| 60 | +The Azure package repository is required to integrate the library: |
| 61 | + |
| 62 | +To add the repository: |
| 63 | + |
| 64 | +1. In your project Gradle scripts, ensure that the following repositories are added. For Android Studio (2020.\*), `repositories` is in `settings.gradle`, under `dependencyResolutionManagement(Gradle version 6.8 or greater)`. For earlier versions of Android Studio (4.\*), `repositories` is in the project-level `build.gradle`, under `allprojects{}`. |
| 65 | + |
| 66 | + ```groovy |
| 67 | + // dependencyResolutionManagement |
| 68 | + repositories { |
| 69 | + ... |
| 70 | + maven { |
| 71 | + url "https://pkgs.dev.azure.com/MicrosoftDeviceSDK/DuoSDK-Public/_packaging/Duo-SDK-Feed/maven/v1" |
| 72 | + } |
| 73 | + ... |
| 74 | + } |
| 75 | + ``` |
| 76 | +
|
| 77 | +1. Sync your project with the Gradle files. To sync the project, on the **File** menu, select **Sync Project With Gradle Files**. |
| 78 | +
|
| 79 | +## Add a button to Activity_main.xml |
| 80 | +
|
| 81 | +In the *app/src/main/res/layout/activity_main.xml* layout file, add the following code to create a button to start the composite: |
| 82 | +
|
| 83 | +```xml |
| 84 | +<?xml version="1.0" encoding="utf-8"?> |
| 85 | +<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" |
| 86 | + xmlns:app="http://schemas.android.com/apk/res-auto" |
| 87 | + xmlns:tools="http://schemas.android.com/tools" |
| 88 | + android:layout_width="match_parent" |
| 89 | + android:layout_height="match_parent" |
| 90 | + tools:context=".MainActivity"> |
| 91 | +
|
| 92 | + <Button |
| 93 | + android:id="@+id/startButton" |
| 94 | + android:layout_width="wrap_content" |
| 95 | + android:layout_height="wrap_content" |
| 96 | + android:text="Launch" |
| 97 | + app:layout_constraintBottom_toBottomOf="parent" |
| 98 | + app:layout_constraintLeft_toLeftOf="parent" |
| 99 | + app:layout_constraintRight_toRightOf="parent" |
| 100 | + app:layout_constraintTop_toTopOf="parent" /> |
| 101 | +
|
| 102 | +</androidx.constraintlayout.widget.ConstraintLayout> |
| 103 | +``` |
| 104 | + |
| 105 | +## Initialize the composite |
| 106 | + |
| 107 | +To initialize the composite: |
| 108 | + |
| 109 | +1. Go to `MainActivity`. |
| 110 | + |
| 111 | +1. Add the following code to initialize your composite components for calling. Replace the string values for properties (kotlin) or functions (java) for `endpoint`, `acsIdentity`, `displayName`, `accessToken` and `ThreadId`. Replace `endpoint` with the URL for your resource as provided by Azure Communication Services. Replace `acsIdentity` and `accessToken` with the values provided by Azure Communication Services when you created the access token and use a relevant displayName. Replace `ThreadId` with the value returned when you created the thread. Remember to add the user to the thread via REST API call, or the az command line interface client before you try to run the quick start sample or the client will be denied access to join the thread. |
| 112 | + |
| 113 | +#### [Kotlin](#tab/kotlin) |
| 114 | + |
| 115 | +```kotlin |
| 116 | +package com.example.uilibraryquickstart.chat |
| 117 | +import android.os.Bundle |
| 118 | +import android.view.View |
| 119 | +import android.view.ViewGroup |
| 120 | +import android.widget.Button |
| 121 | +import androidx.appcompat.app.AlertDialog |
| 122 | +import androidx.appcompat.app.AppCompatActivity |
| 123 | +import com.azure.android.communication.common.CommunicationTokenCredential |
| 124 | +import com.azure.android.communication.common.CommunicationTokenRefreshOptions |
| 125 | +import com.azure.android.communication.ui.chat.ChatAdapter |
| 126 | +import com.azure.android.communication.ui.chat.ChatAdapterBuilder |
| 127 | +import com.azure.android.communication.ui.chat.presentation.ChatCompositeView |
| 128 | + |
| 129 | +class MainActivity : AppCompatActivity() { |
| 130 | + private lateinit var chatAdapter: ChatAdapter |
| 131 | + |
| 132 | + override fun onCreate(savedInstanceState: Bundle?) { |
| 133 | + super.onCreate(savedInstanceState) |
| 134 | + setContentView(R.layout.activity_main) |
| 135 | + val startButton = findViewById<Button>(R.id.startButton) |
| 136 | + startButton.setOnClickListener { l: View? -> |
| 137 | + val communicationTokenRefreshOptions = |
| 138 | + CommunicationTokenRefreshOptions( |
| 139 | + { accessToken }, true |
| 140 | + ) |
| 141 | + val communicationTokenCredential = |
| 142 | + CommunicationTokenCredential(communicationTokenRefreshOptions) |
| 143 | + chatAdapter = ChatAdapterBuilder() |
| 144 | + .endpoint(endpoint) |
| 145 | + .credential(communicationTokenCredential) |
| 146 | + .identity(acsIdentity) |
| 147 | + .displayName(displayName) |
| 148 | + .threadId(threadId) |
| 149 | + .build() |
| 150 | + try { |
| 151 | + chatAdapter.connect(this@MainActivity).get() |
| 152 | + val chatView: View = ChatThreadView(this@MainActivity, chatAdapter) |
| 153 | + addContentView( |
| 154 | + chatView, |
| 155 | + ViewGroup.LayoutParams( |
| 156 | + ViewGroup.LayoutParams.MATCH_PARENT, |
| 157 | + ViewGroup.LayoutParams.MATCH_PARENT |
| 158 | + ) |
| 159 | + ) |
| 160 | + } catch (e: Exception) { |
| 161 | + var messageCause: String? = "Unknown error" |
| 162 | + if (e.cause != null && e.cause!!.message != null) { |
| 163 | + messageCause = e.cause!!.message |
| 164 | + } |
| 165 | + showAlert(messageCause) |
| 166 | + } |
| 167 | + } |
| 168 | + } |
| 169 | + |
| 170 | + /** |
| 171 | + * |
| 172 | + * @return String endpoint URL from ACS Admin UI, "https://example.domain.com/" |
| 173 | + */ |
| 174 | + private val endpoint: String? |
| 175 | + get() = "https://example.domain.com/" |
| 176 | + |
| 177 | + /** |
| 178 | + * |
| 179 | + * @return String identity of the user joining the chat |
| 180 | + * Looks like "8:acs:a6aada1f-0b1e-47ac-866a-91aae00a1c01_00000015-45ee-bad7-0ea8-923e0d008a89" |
| 181 | + */ |
| 182 | + private val acsIdentity: String? |
| 183 | + get() = "" |
| 184 | + |
| 185 | + /** |
| 186 | + * |
| 187 | + * @return String display name of the user joining the chat |
| 188 | + */ |
| 189 | + private val displayName: String? |
| 190 | + get() = "" |
| 191 | + |
| 192 | + /** |
| 193 | + * |
| 194 | + * @return String secure ACS access token for the current user |
| 195 | + */ |
| 196 | + private val accessToken: String? |
| 197 | + get() = "" |
| 198 | + |
| 199 | + /** |
| 200 | + * |
| 201 | + * @return String id of ACS chat thread to join |
| 202 | + * Looks like "19:[email protected]" |
| 203 | + */ |
| 204 | + private val threadId: String? |
| 205 | + get() = "" |
| 206 | + |
| 207 | + fun showAlert(message: String?) { |
| 208 | + runOnUiThread { |
| 209 | + AlertDialog.Builder(this@MainActivity) |
| 210 | + .setMessage(message) |
| 211 | + .setTitle("Alert") |
| 212 | + .setPositiveButton( |
| 213 | + "OK" |
| 214 | + ) { _, i -> } |
| 215 | + .show() |
| 216 | + } |
| 217 | + } |
| 218 | +} |
| 219 | +``` |
| 220 | + |
| 221 | +#### [Java](#tab/java) |
| 222 | + |
| 223 | +```java |
| 224 | +package com.example.uilibraryquickstart.chat; |
| 225 | +import androidx.appcompat.app.AlertDialog; |
| 226 | +import androidx.appcompat.app.AppCompatActivity; |
| 227 | +import android.content.DialogInterface; |
| 228 | +import android.os.Bundle; |
| 229 | +import android.view.View; |
| 230 | +import android.view.ViewGroup; |
| 231 | +import android.widget.Button; |
| 232 | +import com.azure.android.communication.common.CommunicationTokenCredential; |
| 233 | +import com.azure.android.communication.common.CommunicationTokenRefreshOptions; |
| 234 | +import com.azure.android.communication.ui.chat.ChatAdapter; |
| 235 | +import com.azure.android.communication.ui.chat.ChatAdapterBuilder; |
| 236 | +import com.azure.android.communication.ui.chat.presentation.ChatCompositeView; |
| 237 | +public class MainActivity extends AppCompatActivity { |
| 238 | + private ChatAdapter chatAdapter; |
| 239 | + |
| 240 | + @Override |
| 241 | + protected void onCreate(Bundle savedInstanceState) { |
| 242 | + super.onCreate(savedInstanceState); |
| 243 | + setContentView(R.layout.activity_main); |
| 244 | + Button startButton = findViewById(R.id.startButton); |
| 245 | + startButton.setOnClickListener(l -> { |
| 246 | + CommunicationTokenRefreshOptions communicationTokenRefreshOptions = |
| 247 | + new CommunicationTokenRefreshOptions(this::accessToken, true); |
| 248 | + CommunicationTokenCredential communicationTokenCredential = |
| 249 | + new CommunicationTokenCredential(communicationTokenRefreshOptions); |
| 250 | + chatAdapter = new ChatAdapterBuilder() |
| 251 | + .endpoint(endpoint()) |
| 252 | + .credential(communicationTokenCredential) |
| 253 | + .identity(acsIdentity()) |
| 254 | + .displayName(displayName()) |
| 255 | + .threadId(threadId()) |
| 256 | + .build(); |
| 257 | + try { |
| 258 | + chatAdapter.connect(MainActivity.this).get(); |
| 259 | + View chatView = new ChatThreadView(MainActivity.this, chatAdapter); |
| 260 | + addContentView(chatView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)); |
| 261 | + } |
| 262 | + catch (Exception e){ |
| 263 | + String messageCause = "Unknown error"; |
| 264 | + if (e.getCause() != null && e.getCause().getMessage() != null){ |
| 265 | + messageCause = e.getCause().getMessage(); |
| 266 | + } |
| 267 | + showAlert(messageCause); |
| 268 | + } |
| 269 | + }); |
| 270 | + } |
| 271 | + /** |
| 272 | + * |
| 273 | + * @return String endpoint URL from ACS Admin UI, "https://example.domain.com/" |
| 274 | + */ |
| 275 | + private String endpoint(){ |
| 276 | + return "https://example.domain.com/"; |
| 277 | + } |
| 278 | + /** |
| 279 | + * |
| 280 | + * @return String identity of the user joining the chat |
| 281 | + * Looks like "8:acs:a6aada1f-0b1e-47ac-866a-91aae00a1c01_00000015-45ee-bad7-0ea8-923e0d008a89" |
| 282 | + */ |
| 283 | + private String acsIdentity(){ |
| 284 | + return ""; |
| 285 | + } |
| 286 | + /** |
| 287 | + * |
| 288 | + * @return String display name of the user joining the chat |
| 289 | + */ |
| 290 | + private String displayName(){ |
| 291 | + return ""; |
| 292 | + } |
| 293 | + /** |
| 294 | + * |
| 295 | + * @return String secure ACS access token for the current user |
| 296 | + */ |
| 297 | + private String accessToken(){ |
| 298 | + return ""; |
| 299 | + } |
| 300 | + /** |
| 301 | + * |
| 302 | + * @return String id of ACS chat thread to join |
| 303 | + * Looks like "19:[email protected]" |
| 304 | + */ |
| 305 | + private String threadId(){ |
| 306 | + return ""; |
| 307 | + } |
| 308 | + void showAlert(String message){ |
| 309 | + runOnUiThread(new Runnable() { |
| 310 | + @Override |
| 311 | + public void run() { |
| 312 | + new AlertDialog.Builder(MainActivity.this) |
| 313 | + .setMessage(message) |
| 314 | + .setTitle("Alert") |
| 315 | + .setPositiveButton("OK", new DialogInterface.OnClickListener() { |
| 316 | + @Override |
| 317 | + public void onClick(DialogInterface dialogInterface, int i) { |
| 318 | + } |
| 319 | + }) |
| 320 | + .show(); |
| 321 | + } |
| 322 | + }); |
| 323 | + } |
| 324 | +} |
| 325 | +``` |
| 326 | + |
| 327 | +--- |
| 328 | + |
| 329 | +## Run the code |
| 330 | + |
| 331 | +In Android Studio, build and start the application: |
| 332 | + |
| 333 | +1. Select **Start Experience**. |
| 334 | +1. The chat client will join the chat thread and you can start typing and sending messages |
| 335 | +1. If the client is not able to join the thread, and you see chatJoin failed errors, verify that your user's access token is valid and that the user has been added to the chat thread by REST API call, or by using the `az` command line interface. |
| 336 | + |
| 337 | +:::image type="content" source="../../media/quickstart-chat.gif" alt-text="GIF animation that shows an example of how the project runs on an Android device."::: |
0 commit comments