Build an Android messenger app with online presence using Kotlin
Tags: pusher, kotlin, node, realtime
Published: 2018-11-20 06:46:57

---
title: Build an Android messenger app with online presence using Kotlin
published: true
description: 
tags: pusher, kotlin, Node.js, realtime
---

> You will need Android Studio 3+, Node, npm and MongoDB installed on your machine. Some familiarity with Android development is required.

When building a chat application, it is essential to have an online presence feature. It is essential because your users will like to know when their friends are online and are more likely to respond to their messages.

In this article, we will be building a messenger app with online presence using Pusher Channels, Kotlin and Node.js.

Here is a demo of what we will build:

![](//images.ctfassets.net/1es3ne0caaid/mmdMFfq7WoYsk26cIKocs/486ce2b458e45a41cfeb01ab4441f3b4/android-messenger-presence-demo.gif)

# Prerequisites

To follow along you need the following requirements:

- A Pusher Channel app. You can create one [here](https://pusher.com/channels).
- Android Studio installed on your machine. You can check [here](https://developer.android.com/studio/index.html) for the latest stable version. A minimum of version 3.0 is recommended.
- Basic knowledge of Android development and the Android Studio IDE.
- Basic knowledge of Kotlin. Here are the [official docs](https://kotlinlang.org/docs/reference/).
- Node.js and NPM (Node Package Manager) installed on your machine. Download [here](https://nodejs.org/en/).
- Mongo DB installed on your machine. You can install it following the instructions [here](https://docs.mongodb.com/manual/installation/).

## Building the backend server

Our server will be built using Node.js. To start, create a new project directory:

```
    $ mkdir backend-server

```

Next, create a new `index.js` file inside the project directory and paste the following code:

```
    <span class="hljs-comment">// File: ./index.js</span>
    <span class="hljs-keyword">var</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">'express'</span>);
    <span class="hljs-keyword">var</span> bodyParser = <span class="hljs-built_in">require</span>(<span class="hljs-string">'body-parser'</span>);
    <span class="hljs-keyword">const</span> mongoose = <span class="hljs-built_in">require</span>(<span class="hljs-string">'mongoose'</span>);
    <span class="hljs-keyword">var</span> Pusher = <span class="hljs-built_in">require</span>(<span class="hljs-string">'pusher'</span>);

    <span class="hljs-keyword">var</span> app = express();

    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ <span class="hljs-attr">extended</span>: <span class="hljs-literal">false</span> }));

    <span class="hljs-keyword">var</span> pusher = <span class="hljs-keyword">new</span> Pusher({
      <span class="hljs-attr">appId</span>: <span class="hljs-string">'PUSHER_APP_ID'</span>,
      <span class="hljs-attr">key</span>: <span class="hljs-string">'PUSHER_APP_KEY'</span>,
      <span class="hljs-attr">secret</span>: <span class="hljs-string">'PUSHER_APP_SECRET'</span>,
      <span class="hljs-attr">cluster</span>: <span class="hljs-string">'PUSHER_APP_CLUSTER'</span>
    });

    mongoose.connect(<span class="hljs-string">'mongodb://127.0.0.1/db'</span>);

    <span class="hljs-keyword">const</span> Schema = mongoose.Schema;
    <span class="hljs-keyword">const</span> userSchema = <span class="hljs-keyword">new</span> Schema({
        <span class="hljs-attr">name</span>: { <span class="hljs-attr">type</span>: <span class="hljs-built_in">String</span>, <span class="hljs-attr">required</span>: <span class="hljs-literal">true</span>, },
        <span class="hljs-attr">count</span>: {<span class="hljs-attr">type</span>: <span class="hljs-built_in">Number</span>}
    });

    <span class="hljs-keyword">var</span> User = mongoose.model(<span class="hljs-string">'User'</span>, userSchema);
    userSchema.pre(<span class="hljs-string">'save'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">next</span>) </span>{
        <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.isNew) {
            User.count().then(<span class="hljs-function"><span class="hljs-params">res</span> =></span> {
              <span class="hljs-keyword">this</span>.count = res; <span class="hljs-comment">// Increment count</span>
              next();
            });
          } <span class="hljs-keyword">else</span> {
            next();
          }
    });

    <span class="hljs-built_in">module</span>.exports = User;

    <span class="hljs-keyword">var</span> currentUser;

    <span class="hljs-comment">/* 
    =================================
    We will add our endpoints here!!!
    =================================
    */</span>

    <span class="hljs-keyword">var</span> port = process.env.PORT || <span class="hljs-number">5000</span>;

    app.listen(port);
```

In the snippet above, we initialized Pusher, Express, and MongoDB. We are using [Moongose](http://mongoosejs.com/) to connect to our MongoDB instance.

> Replace the `PUSHER_APP_*` keys with the ones on your Pusher dashboard.

Now let’s add our endpoints. The first endpoint we will add will be to log a user in. Paste the code below in your `index.js` file below the `currentUser` declaration:

```
    <span class="hljs-comment">// File: ./index.js</span>

    <span class="hljs-comment">// [...]</span>

    app.post(<span class="hljs-string">'/login'</span>, (req,res) => {
        User.findOne({<span class="hljs-attr">name</span>: req.body.name}, (err, user) => {
            <span class="hljs-keyword">if</span> (err) {
                res.send(<span class="hljs-string">"Error connecting to database"</span>);
            }

            <span class="hljs-comment">// User exists</span>
            <span class="hljs-keyword">if</span> (user) {
                currentUser = user;
                <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).send(user)
            }

            <span class="hljs-keyword">let</span> newuser = <span class="hljs-keyword">new</span> User({<span class="hljs-attr">name</span>: req.body.name});

            newuser.save(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">err</span>) </span>{
                <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">throw</span> err;
            });

            currentUser = newuser;
            res.status(<span class="hljs-number">200</span>).send(newuser)
        });
    })

    <span class="hljs-comment">// [...]</span>
```

This endpoint receives a `username` with the request, and either create a new user or returns the data of the existing user.

Let’s add the next endpoint below the one above:

```
    <span class="hljs-comment">// File: ./index.js</span>

    <span class="hljs-comment">// [...]</span>

    app.get(<span class="hljs-string">'/users'</span>, (req,res) => {
        User.find({}, (err, users) => {
            <span class="hljs-keyword">if</span> (err) <span class="hljs-keyword">throw</span> err;
            res.send(users);
        });
    })

    <span class="hljs-comment">// [...]</span>
```

This endpoint above fetches all the users from the database and returns them.

Since we will be using a Pusher presence channel, we need an endpoint to authenticate the user. In the same file, paste this code below the endpoint above:

```
    <span class="hljs-comment">// File: ./index.js</span>

    <span class="hljs-comment">// [...]</span>

    app.post(<span class="hljs-string">'/pusher/auth/presence'</span>, (req, res) => {
        <span class="hljs-keyword">let</span> socketId = req.body.socket_id;
        <span class="hljs-keyword">let</span> channel = req.body.channel_name;

        <span class="hljs-keyword">let</span> presenceData = {
            <span class="hljs-attr">user_id</span>: currentUser._id,
            <span class="hljs-attr">user_info</span>: {<span class="hljs-attr">count</span>: currentUser.count, <span class="hljs-attr">name</span>: currentUser.name}
        };

        <span class="hljs-keyword">let</span> auth = pusher.authenticate(socketId, channel, presenceData);

        res.send(auth);
    });

    <span class="hljs-comment">// [...]</span>
```

Since we are going to be using private channels, we need an endpoint for authentication. Add the following endpoint below the endpoint above:

```
    <span class="hljs-comment">// File: ./index.js</span>

    <span class="hljs-comment">// [...]</span>

    app.post(<span class="hljs-string">'/pusher/auth/private'</span>, (req, res) => {
        res.send(pusher.authenticate(req.body.socket_id, req.body.channel_name));
    });

    <span class="hljs-comment">// [...]</span>

Finally, the last endpoint will be to trigger an event <span class="hljs-string">`new-message`</span> to a channel. Add the endpoint below the last one:


    <span class="hljs-comment">// File: ./index.js</span>

    <span class="hljs-comment">// [...]</span>

    app.post(<span class="hljs-string">'/send-message'</span>, (req, res) => {
        <span class="hljs-keyword">let</span> payload = {<span class="hljs-attr">message</span>: req.body.message, <span class="hljs-attr">sender_id</span>: req.body.sender_id}
        pusher.trigger(req.body.channel_name, <span class="hljs-string">'new-message'</span>, payload);
        res.send(<span class="hljs-number">200</span>);
    });

    <span class="hljs-comment">// [...]</span>
```

After adding all the endpoints, install the necessary NPM packages by running this command:

```
    $ npm install express body-parser mongoose pusher

```

Before you run your application, make sure MongoDB is running already using this command:

```
    $ mongod --dbpath C:\MongoDB\data\db # Windows
    $ mongod --dbpath=/path/to/db/directory # Mac or Linux

```

Now you can run your application using the command below:

```
    $ node index.js

```

Your app will be available here: <http://localhost:5000>.

## Building our Android application

Create your Android project. In the wizard, enter your project name, let’s say **MessengerApp.** Next, enter your package name. You can use a minimum SDK of 19 then choose an **Empty Activity**. On the next page, change the **Activity Name** to `LoginActivity`. After this, Android Studio will build your project for you.

Now that we have the project, let’s add the required dependencies for our app. Open your app module `build.gradle` file and add these:

```
    // File ../app/build.gradle
    dependencies {
      // [...]

      implementation 'com.android.support:design:28+'
      implementation 'com.pusher:pusher-java-client:1.6.0'
      implementation "com.squareup.retrofit2:retrofit:2.4.0"
      implementation "com.squareup.retrofit2:converter-scalars:2.4.0"
      implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
    }

```

Notably, we added the dependencies for [Retrofit](http://square.github.io/retrofit/) and Pusher. Retrofit is an HTTP client library used for network calls. We added the design library dependency too as we want to use some classes from it. Sync your gradle files to pull in the dependencies.

Next, let’s prepare our app to make network calls. Retrofit requires an interface to know the endpoints to be accessed.

Create a new interface named `ApiService` and paste this:

```
    <span class="hljs-comment">// File: ./app/src/main/java/com/example/messengerapp/ApiService.kt</span>
    <span class="hljs-keyword">import</span> okhttp3.RequestBody
    <span class="hljs-keyword">import</span> retrofit2.Call
    <span class="hljs-keyword">import</span> retrofit2.http.Body
    <span class="hljs-keyword">import</span> retrofit2.http.GET
    <span class="hljs-keyword">import</span> retrofit2.http.POST

    <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">ApiService</span> </span>{

      <span class="hljs-meta">@POST(<span class="hljs-meta-string">"/login"</span>)</span>
      <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">login</span><span class="hljs-params">(<span class="hljs-meta">@Body</span> body:<span class="hljs-type">RequestBody</span>)</span></span>: Call<UserModel>

      <span class="hljs-meta">@POST(<span class="hljs-meta-string">"/send-message"</span>)</span>
      <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">sendMessage</span><span class="hljs-params">(<span class="hljs-meta">@Body</span> body:<span class="hljs-type">RequestBody</span>)</span></span>: Call<String>

      <span class="hljs-meta">@GET(<span class="hljs-meta-string">"/users"</span>)</span>
      <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getUsers</span><span class="hljs-params">()</span></span>: Call<List<UserModel>>
    }
```

Here, we have declared three endpoints. They are for logging in, sending messages and fetching users. Notice that in some of our responses, we return `Call<UserModel>`. Let’s create the `UserModel`. Create a new class called `UserModel` and paste the following:

```
    <span class="hljs-comment">// File: ./app/src/main/java/com/example/messengerapp/UserModel.kt</span>
    <span class="hljs-keyword">import</span> com.google.gson.annotations.Expose
    <span class="hljs-keyword">import</span> com.google.gson.annotations.SerializedName

    <span class="hljs-keyword">data</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserModel</span></span>(<span class="hljs-meta">@SerializedName(<span class="hljs-meta-string">"_id"</span>)</span> <span class="hljs-meta">@Expose</span> <span class="hljs-keyword">var</span> id: String,
                         <span class="hljs-meta">@SerializedName(<span class="hljs-meta-string">"name"</span>)</span> <span class="hljs-meta">@Expose</span> <span class="hljs-keyword">var</span> name: String,
                         <span class="hljs-meta">@SerializedName(<span class="hljs-meta-string">"count"</span>)</span> <span class="hljs-meta">@Expose</span> <span class="hljs-keyword">var</span> count: <span class="hljs-built_in">Int</span>,
                         <span class="hljs-keyword">var</span> online:<span class="hljs-built_in">Boolean</span> = <span class="hljs-literal">false</span>)
```

Above, we used a data class so that some other functions required for model classes such as `toString`, `hashCode` are added to the class by default.

We are expecting only the values for the `id` and `name` from the server. We added the `online` property so we can update later on.

Next, create a new class named `RetrofitInstance` and paste the following code:

```
    <span class="hljs-comment">// File: ./app/src/main/java/com/example/messengerapp/RetrofitInstance.kt</span>
    <span class="hljs-keyword">import</span> okhttp3.OkHttpClient
    <span class="hljs-keyword">import</span> retrofit2.Retrofit
    <span class="hljs-keyword">import</span> retrofit2.converter.gson.GsonConverterFactory
    <span class="hljs-keyword">import</span> retrofit2.converter.scalars.ScalarsConverterFactory

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RetrofitInstance</span> </span>{

      <span class="hljs-keyword">companion</span> <span class="hljs-keyword">object</span> {
        <span class="hljs-keyword">val</span> retrofit: ApiService <span class="hljs-keyword">by</span> lazy {
          <span class="hljs-keyword">val</span> httpClient = OkHttpClient.Builder()
          <span class="hljs-keyword">val</span> builder = Retrofit.Builder()
              .baseUrl(<span class="hljs-string">"http://10.0.2.2:5000/"</span>)
              .addConverterFactory(ScalarsConverterFactory.create())
              .addConverterFactory(GsonConverterFactory.create())

          <span class="hljs-keyword">val</span> retrofit = builder
              .client(httpClient.build())
              .build()
          retrofit.create(ApiService::<span class="hljs-class"><span class="hljs-keyword">class</span>.<span class="hljs-title">java</span>)</span>
        }
      }
    }
```

This class contains a class variable called `retrofit`. It provides us with an instance for Retrofit that we will reference in more than one class.

Finally, to request for the internet access permission update the `AndroidManifest.xml` file like so:

```
    <span class="hljs-comment">// File: ./app/src/main/ApiService.kt</span>
    <manifest xmlns:android=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
      <span class="hljs-keyword">package</span>=<span class="hljs-string">"com.example.messengerapp"</span>>

      <uses-permission android:name=<span class="hljs-string">"android.permission.INTERNET"</span> />
      [...]

    </manifest>
```

Now we can make requests using Retrofit.

The next feature we will implement is login. Open the already created `LoginActivity` layout file `activity_login.xml` file and paste this:

```
    // File: ./app/src/main/res/layout/activity_login.xml
    <span class="hljs-meta"><?xml version="1.0" encoding="utf-8"?></span>
    <span class="hljs-tag"><<span class="hljs-name">android.support.constraint.ConstraintLayout</span> <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
      <span class="hljs-attr">xmlns:app</span>=<span class="hljs-string">"http://schemas.android.com/apk/res-auto"</span>
      <span class="hljs-attr">xmlns:tools</span>=<span class="hljs-string">"http://schemas.android.com/tools"</span>
      <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
      <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"match_parent"</span>
      <span class="hljs-attr">android:layout_margin</span>=<span class="hljs-string">"20dp"</span>
      <span class="hljs-attr">tools:context</span>=<span class="hljs-string">".LoginActivity"</span>></span>

      <span class="hljs-tag"><<span class="hljs-name">EditText</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/editTextUsername"</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">app:layout_constraintBottom_toBottomOf</span>=<span class="hljs-string">"parent"</span>
        <span class="hljs-attr">app:layout_constraintLeft_toLeftOf</span>=<span class="hljs-string">"parent"</span>
        <span class="hljs-attr">app:layout_constraintRight_toRightOf</span>=<span class="hljs-string">"parent"</span>
        <span class="hljs-attr">app:layout_constraintTop_toTopOf</span>=<span class="hljs-string">"parent"</span> /></span>

      <span class="hljs-tag"><<span class="hljs-name">Button</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/loginButton"</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">android:text</span>=<span class="hljs-string">"Login"</span>
        <span class="hljs-attr">app:layout_constraintTop_toBottomOf</span>=<span class="hljs-string">"@+id/editTextUsername"</span> /></span>

    <span class="hljs-tag"></<span class="hljs-name">android.support.constraint.ConstraintLayout</span>></span>
```

This layout contains an input field to take the username and a button to make a login request.

Next, open the `LoginActivity.Kt` file and paste this:

```
    <span class="hljs-comment">// File: ./app/src/main/java/com/example/messengerapp/LoginActivity.kt</span>
    <span class="hljs-keyword">import</span> android.content.Intent
    <span class="hljs-keyword">import</span> android.os.Bundle
    <span class="hljs-keyword">import</span> android.support.v7.app.AppCompatActivity
    <span class="hljs-keyword">import</span> android.util.Log
    <span class="hljs-keyword">import</span> kotlinx.android.synthetic.main.activity_login.*
    <span class="hljs-keyword">import</span> okhttp3.MediaType
    <span class="hljs-keyword">import</span> okhttp3.RequestBody
    <span class="hljs-keyword">import</span> org.json.JSONObject
    <span class="hljs-keyword">import</span> retrofit2.Call
    <span class="hljs-keyword">import</span> retrofit2.Callback
    <span class="hljs-keyword">import</span> retrofit2.Response

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">LoginActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)
        loginButton.setOnClickListener {
          <span class="hljs-keyword">if</span> (editTextUsername.text.isNotEmpty()) {
            loginFunction(editTextUsername.text.toString())
          }
        }
      }

      <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">loginFunction</span><span class="hljs-params">(name:<span class="hljs-type">String</span>)</span></span> {
        <span class="hljs-keyword">val</span> jsonObject = JSONObject()
        jsonObject.put(<span class="hljs-string">"name"</span>, name)

        <span class="hljs-keyword">val</span> jsonBody = RequestBody.create(
            MediaType.parse(<span class="hljs-string">"application/json; charset=utf-8"</span>), 
            jsonObject.toString()
        )

        RetrofitInstance.retrofit.login(jsonBody).enqueue(<span class="hljs-keyword">object</span>:Callback<UserModel> {
          <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onFailure</span><span class="hljs-params">(call: <span class="hljs-type">Call</span><<span class="hljs-type">UserModel</span>>?, t: <span class="hljs-type">Throwable</span>?)</span></span> {
            Log.i(<span class="hljs-string">"LoginActivity"</span>,t!!.localizedMessage)
          }

          <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onResponse</span><span class="hljs-params">(call: <span class="hljs-type">Call</span><<span class="hljs-type">UserModel</span>>?, response: <span class="hljs-type">Response</span><<span class="hljs-type">UserModel</span>>?)</span></span> {
            <span class="hljs-keyword">if</span> (response!!.code() == <span class="hljs-number">200</span>) {
              Singleton.getInstance().currentUser = response.body()!!
              startActivity(Intent(<span class="hljs-keyword">this</span><span class="hljs-symbol">@LoginActivity</span>,ContactListActivity::<span class="hljs-class"><span class="hljs-keyword">class</span>.<span class="hljs-title">java</span>))</span>
              finish()
            }
          }
        })
      }
    }
```

In the file, we set up a listener for our login button so that when it is clicked, we can send the text to the server for authentication. We also stored the logged in user in a singleton class so that we can access the user’s details later.

Create a new class called `Singleton` and paste this:

```
    <span class="hljs-comment">// File: ./app/src/main/java/com/example/messengerapp/RetrofitInstance.kt</span>
    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Singleton</span> </span>{
      <span class="hljs-keyword">companion</span> <span class="hljs-keyword">object</span> {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> ourInstance = Singleton()
        <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getInstance</span><span class="hljs-params">()</span></span>: Singleton {
          <span class="hljs-keyword">return</span> ourInstance
        }
      }
      <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> currentUser: UserModel
    }
```

With this class, we will have access to the `currentUser`, which is the logged in user.

Next, let’s create a new activity named `ContactListActivity`. For now, leave the class empty and open the corresponding layout file named `activity_contact_list` and paste the following:

```
    // File: ./app/src/main/res/layout/activity_contact_list.xml
    <span class="hljs-meta"><?xml version="1.0" encoding="utf-8"?></span>
    <span class="hljs-tag"><<span class="hljs-name">android.support.constraint.ConstraintLayout</span> <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
      <span class="hljs-attr">xmlns:app</span>=<span class="hljs-string">"http://schemas.android.com/apk/res-auto"</span>
      <span class="hljs-attr">xmlns:tools</span>=<span class="hljs-string">"http://schemas.android.com/tools"</span>
      <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
      <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"match_parent"</span>
      <span class="hljs-attr">tools:context</span>=<span class="hljs-string">".ContactListActivity"</span>></span>

      <span class="hljs-tag"><<span class="hljs-name">android.support.v7.widget.RecyclerView</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/recyclerViewUserList"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"match_parent"</span>/></span>

    <span class="hljs-tag"></<span class="hljs-name">android.support.constraint.ConstraintLayout</span>></span>
```

The layout contains a recycler view, which will give us all the list of our contacts fetched from the database. Since we are displaying items in a list, we will need an adapter class to manage how items are inflated to the layout.

Create a new class named `ContactRecyclerAdapter` and paste this:

```
    <span class="hljs-comment">// File: ./app/src/main/java/com/example/messengerapp/ContactRecyclerAdapter.kt</span>
    <span class="hljs-keyword">import</span> android.support.v7.widget.RecyclerView
    <span class="hljs-keyword">import</span> android.view.LayoutInflater
    <span class="hljs-keyword">import</span> android.view.View
    <span class="hljs-keyword">import</span> android.view.ViewGroup
    <span class="hljs-keyword">import</span> android.widget.ImageView
    <span class="hljs-keyword">import</span> android.widget.TextView
    <span class="hljs-keyword">import</span> java.util.*

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ContactRecyclerAdapter</span></span>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> list: ArrayList<UserModel>, <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> listener: UserClickListener)
      : RecyclerView.Adapter<ContactRecyclerAdapter.ViewHolder>() {

      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreateViewHolder</span><span class="hljs-params">(parent: <span class="hljs-type">ViewGroup</span>, viewType: <span class="hljs-type">Int</span>)</span></span>: ViewHolder {
        <span class="hljs-keyword">return</span> ViewHolder(LayoutInflater.from(parent.context)
            .inflate(R.layout.user_list_row, parent, <span class="hljs-literal">false</span>))
      }

      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onBindViewHolder</span><span class="hljs-params">(holder: <span class="hljs-type">ViewHolder</span>, position: <span class="hljs-type">Int</span>)</span></span> = holder.bind(list[position])

      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getItemCount</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Int</span> = list.size

      <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showUserOnline</span><span class="hljs-params">(updatedUser: <span class="hljs-type">UserModel</span>)</span></span> {
        list.forEachIndexed { index, element ->
          <span class="hljs-keyword">if</span> (updatedUser.id == element.id) {
            updatedUser.online = <span class="hljs-literal">true</span>
            list[index] = updatedUser
            notifyItemChanged(index)
          }

        }
      }

      <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">showUserOffline</span><span class="hljs-params">(updatedUser: <span class="hljs-type">UserModel</span>)</span></span> {
        list.forEachIndexed { index, element ->
          <span class="hljs-keyword">if</span> (updatedUser.id == element.id) {
            updatedUser.online = <span class="hljs-literal">false</span>
            list[index] = updatedUser
            notifyItemChanged(index)
          }
        }
      }

      <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">add</span><span class="hljs-params">(user: <span class="hljs-type">UserModel</span>)</span></span> {
        list.add(user)
        notifyDataSetChanged()
      }

      <span class="hljs-keyword">inner</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ViewHolder</span></span>(itemView: View) : RecyclerView.ViewHolder(itemView) {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> nameTextView: TextView = itemView.findViewById(R.id.usernameTextView)
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> presenceImageView: ImageView = itemView.findViewById(R.id.presenceImageView)

        <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">bind</span><span class="hljs-params">(currentValue: <span class="hljs-type">UserModel</span>)</span></span> = with(itemView) {
          <span class="hljs-keyword">this</span>.setOnClickListener {
            listener.onUserClicked(currentValue)
          }
          nameTextView.text = currentValue.name
          <span class="hljs-keyword">if</span> (currentValue.online){
            presenceImageView.setImageDrawable(<span class="hljs-keyword">this</span>.context.resources.getDrawable(R.drawable.presence_icon_online))
          } <span class="hljs-keyword">else</span> {
            presenceImageView.setImageDrawable(<span class="hljs-keyword">this</span>.context.resources.getDrawable(R.drawable.presence_icon))

          }

        }
      }

      <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">UserClickListener</span> </span>{
        <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onUserClicked</span><span class="hljs-params">(user: <span class="hljs-type">UserModel</span>)</span></span>
      }
    }
```

This adapter has some overridden methods and some custom methods.

The `onCreateViewHolder` inflates how each row will look like. `onBindViewHolder` binds the data to each item by calling the `bind` method in the inner `ViewHolder` class. The `getItemCount` gives the size of the list.

For our custom methods, `showUserOffline` updates the user and shows when they are offline. While `showUserOnline` does the opposite. Finally, we have the `add` method, which adds a new contact to the list and refreshes it.

In the adapter class above, we used a new layout named `user_list_row`. Create a new layout `user_list_row` and paste this:

```
    // File: ./app/src/main/res/layout/user_list_row.xml
    <span class="hljs-meta"><?xml version="1.0" encoding="utf-8"?></span>
    <span class="hljs-tag"><<span class="hljs-name">LinearLayout</span>
      <span class="hljs-attr">android:orientation</span>=<span class="hljs-string">"horizontal"</span>
      <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
      <span class="hljs-attr">xmlns:app</span>=<span class="hljs-string">"http://schemas.android.com/apk/res-auto"</span>
      <span class="hljs-attr">xmlns:tools</span>=<span class="hljs-string">"http://schemas.android.com/tools"</span>
      <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
      <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
      <span class="hljs-attr">android:layout_margin</span>=<span class="hljs-string">"20dp"</span>
      <span class="hljs-attr">android:gravity</span>=<span class="hljs-string">"center"</span>
      <span class="hljs-attr">tools:context</span>=<span class="hljs-string">".LoginActivity"</span>></span>

      <span class="hljs-tag"><<span class="hljs-name">ImageView</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/presenceImageView"</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"15dp"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"15dp"</span>
        <span class="hljs-attr">app:srcCompat</span>=<span class="hljs-string">"@drawable/presence_icon"</span> /></span>

      <span class="hljs-tag"><<span class="hljs-name">TextView</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">tools:text</span>=<span class="hljs-string">"Neo"</span>
        <span class="hljs-attr">android:textSize</span>=<span class="hljs-string">"20sp"</span>
        <span class="hljs-attr">android:layout_marginStart</span>=<span class="hljs-string">"10dp"</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/usernameTextView"</span>
        <span class="hljs-attr">app:layout_constraintTop_toBottomOf</span>=<span class="hljs-string">"@+id/editTextUsername"</span>
        /></span>

    <span class="hljs-tag"></<span class="hljs-name">LinearLayout</span>></span>
```

This layout is the visual representation of how each item on the layout will look like. The layout has an image view that shows the users online status. The layout also has a textview that shows the name of the contact beside the icon. The icons are vector drawables. Let’s create the files.

Create a new drawable named `presence_icon_online` and paste this:

```
    // File: ./app/src/main/res/drawable/presence_icon_online.xml
    <span class="hljs-tag"><<span class="hljs-name">vector</span> <span class="hljs-attr">android:height</span>=<span class="hljs-string">"24dp"</span> <span class="hljs-attr">android:tint</span>=<span class="hljs-string">"#3FFC3C"</span>
        <span class="hljs-attr">android:viewportHeight</span>=<span class="hljs-string">"24.0"</span> <span class="hljs-attr">android:viewportWidth</span>=<span class="hljs-string">"24.0"</span>
        <span class="hljs-attr">android:width</span>=<span class="hljs-string">"24dp"</span> <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>></span>
        <span class="hljs-tag"><<span class="hljs-name">path</span> <span class="hljs-attr">android:fillColor</span>=<span class="hljs-string">"#FF000000"</span> <span class="hljs-attr">android:pathData</span>=<span class="hljs-string">"M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2z"</span>/></span>
    <span class="hljs-tag"></<span class="hljs-name">vector</span>></span>
```

Create another drawable named `presence_icon` and paste this:

```
    // File: ./app/src/main/res/drawable/presence_icon.xml
    <span class="hljs-tag"><<span class="hljs-name">vector</span> <span class="hljs-attr">android:height</span>=<span class="hljs-string">"24dp"</span> <span class="hljs-attr">android:tint</span>=<span class="hljs-string">"#C0C0C6"</span>
        <span class="hljs-attr">android:viewportHeight</span>=<span class="hljs-string">"24.0"</span> <span class="hljs-attr">android:viewportWidth</span>=<span class="hljs-string">"24.0"</span>
        <span class="hljs-attr">android:width</span>=<span class="hljs-string">"24dp"</span> <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>></span>
        <span class="hljs-tag"><<span class="hljs-name">path</span> <span class="hljs-attr">android:fillColor</span>=<span class="hljs-string">"#FF000000"</span> <span class="hljs-attr">android:pathData</span>=<span class="hljs-string">"M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2z"</span>/></span>
    <span class="hljs-tag"></<span class="hljs-name">vector</span>></span>
```

Next, open the `ContactListActivity` class and paste this:

```
    <span class="hljs-comment">// File: ./app/src/main/java/com/example/messengerapp/ContactListActivity.kt</span>
    <span class="hljs-keyword">import</span> android.content.Intent
    <span class="hljs-keyword">import</span> android.os.Bundle
    <span class="hljs-keyword">import</span> android.support.v7.app.AppCompatActivity
    <span class="hljs-keyword">import</span> android.support.v7.widget.LinearLayoutManager
    <span class="hljs-keyword">import</span> android.util.Log
    <span class="hljs-keyword">import</span> com.pusher.client.Pusher
    <span class="hljs-keyword">import</span> com.pusher.client.PusherOptions
    <span class="hljs-keyword">import</span> com.pusher.client.channel.PresenceChannelEventListener
    <span class="hljs-keyword">import</span> com.pusher.client.channel.User
    <span class="hljs-keyword">import</span> com.pusher.client.util.HttpAuthorizer
    <span class="hljs-keyword">import</span> kotlinx.android.synthetic.main.activity_contact_list.*
    <span class="hljs-keyword">import</span> retrofit2.Call
    <span class="hljs-keyword">import</span> retrofit2.Callback
    <span class="hljs-keyword">import</span> retrofit2.Response

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ContactListActivity</span> : <span class="hljs-type">AppCompatActivity</span></span>(),
        ContactRecyclerAdapter.UserClickListener {

      <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> mAdapter = ContactRecyclerAdapter(ArrayList(), <span class="hljs-keyword">this</span>)

      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_contact_list)
        setupRecyclerView()
        fetchUsers()
        subscribeToChannel()
      }

    }
```

In this class, we initialized the `ContactRecyclerAdapter`, then called three functions in the `onCreate` method. Let’s create these new functions.

In the same class, add the following methods:

```
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setupRecyclerView</span><span class="hljs-params">()</span></span> {
      with(recyclerViewUserList) {
        layoutManager = LinearLayoutManager(<span class="hljs-keyword">this</span><span class="hljs-symbol">@ContactListActivity</span>)
        adapter = mAdapter
      }
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">fetchUsers</span><span class="hljs-params">()</span></span> {
      RetrofitInstance.retrofit.getUsers().enqueue(<span class="hljs-keyword">object</span> : Callback<List<UserModel>> {
        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onFailure</span><span class="hljs-params">(call: <span class="hljs-type">Call</span><<span class="hljs-type">List</span><<span class="hljs-type">UserModel</span>>>?, t: <span class="hljs-type">Throwable</span>?)</span></span> {}
        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onResponse</span><span class="hljs-params">(call: <span class="hljs-type">Call</span><<span class="hljs-type">List</span><<span class="hljs-type">UserModel</span>>>?, response: <span class="hljs-type">Response</span><<span class="hljs-type">List</span><<span class="hljs-type">UserModel</span>>>?)</span></span> {
          <span class="hljs-keyword">for</span> (user <span class="hljs-keyword">in</span> response!!.body()!!) {
            <span class="hljs-keyword">if</span> (user.id != Singleton.getInstance().currentUser.id) {
              mAdapter.add(user)
            }
          }
        }
      })
    }

    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">subscribeToChannel</span><span class="hljs-params">()</span></span> {

      <span class="hljs-keyword">val</span> authorizer = HttpAuthorizer(<span class="hljs-string">"http://10.0.2.2:5000/pusher/auth/presence"</span>)
      <span class="hljs-keyword">val</span> options = PusherOptions().setAuthorizer(authorizer)
      options.setCluster(<span class="hljs-string">"PUSHER_APP_CLUSTER"</span>)

      <span class="hljs-keyword">val</span> pusher = Pusher(<span class="hljs-string">"PUSHER_APP_KEY"</span>, options)
      pusher.connect()

      pusher.subscribePresence(<span class="hljs-string">"presence-channel"</span>, <span class="hljs-keyword">object</span> : PresenceChannelEventListener {
        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onUsersInformationReceived</span><span class="hljs-params">(p0: <span class="hljs-type">String</span>?, users: <span class="hljs-type">MutableSet</span><<span class="hljs-type">User</span>>?)</span></span> {
          <span class="hljs-keyword">for</span> (user <span class="hljs-keyword">in</span> users!!) {
            <span class="hljs-keyword">if</span> (user.id!=Singleton.getInstance().currentUser.id){
              runOnUiThread {
                mAdapter.showUserOnline(user.toUserModel())
              }
            }
          }
        }

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onEvent</span><span class="hljs-params">(p0: <span class="hljs-type">String</span>?, p1: <span class="hljs-type">String</span>?, p2: <span class="hljs-type">String</span>?)</span></span> {}
        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAuthenticationFailure</span><span class="hljs-params">(p0: <span class="hljs-type">String</span>?, p1: <span class="hljs-type">Exception</span>?)</span></span> {}
        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onSubscriptionSucceeded</span><span class="hljs-params">(p0: <span class="hljs-type">String</span>?)</span></span> {}

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">userSubscribed</span><span class="hljs-params">(channelName: <span class="hljs-type">String</span>, user: <span class="hljs-type">User</span>)</span></span> {
          runOnUiThread {
            mAdapter.showUserOnline(user.toUserModel())
          }
        }

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">userUnsubscribed</span><span class="hljs-params">(channelName: <span class="hljs-type">String</span>, user: <span class="hljs-type">User</span>)</span></span> {
          runOnUiThread {
            mAdapter.showUserOffline(user.toUserModel())
          }
        }
      })
    }

    <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onUserClicked</span><span class="hljs-params">(user: <span class="hljs-type">UserModel</span>)</span></span> {
      <span class="hljs-keyword">val</span> intent = Intent(<span class="hljs-keyword">this</span>, ChatRoom::<span class="hljs-class"><span class="hljs-keyword">class</span>.<span class="hljs-title">java</span>)</span>
      intent.putExtra(ChatRoom.EXTRA_ID,user.id)
      intent.putExtra(ChatRoom.EXTRA_NAME,user.name)
      intent.putExtra(ChatRoom.EXTRA_COUNT,user.count)
      startActivity(intent)
    }
```

> Replace the `PUSHER_APP_*` keys with the values on your dashboard.

- `setupRecyclerView` assigns a layout manager and an adapter to the recycler view. For a recycler view to work, you need these two things.
- `fetchUsers` fetches all the users from the server and displays on the list. It exempts the current user logged in.
- `subcribeToChannel` subscribes to a presence channel. When you subscribe to one, the `onUsersInformationReceived` gives you all the users subscribed to the channel including the current user. So, in that callback, we call the `showUserOnline` method in the adapter class so that the icon beside the user can be changed to signify that the user is online.
- `onUserClicked` is called when a contact is selected. We pass the details of the user to the next activity called `ChatRoom`.

In the previous snippet, we used an extension function to transform the `User` object we receive from Pusher to our own `UserModel` object. Let’s define this extension.

Create a new class called `Utils` and paste this:

```
    <span class="hljs-comment">// File: ./app/src/main/java/com/example/messengerapp/Utils.kt</span>
    <span class="hljs-keyword">import</span> com.pusher.client.channel.User
    <span class="hljs-keyword">import</span> org.json.JSONObject

    <span class="hljs-function"><span class="hljs-keyword">fun</span> User.<span class="hljs-title">toUserModel</span><span class="hljs-params">()</span></span>:UserModel{
      <span class="hljs-keyword">val</span> jsonObject = JSONObject(<span class="hljs-keyword">this</span>.info)
      <span class="hljs-keyword">val</span> name = jsonObject.getString(<span class="hljs-string">"name"</span>)
      <span class="hljs-keyword">val</span> numb = jsonObject.getInt(<span class="hljs-string">"count"</span>)
      <span class="hljs-keyword">return</span> UserModel(<span class="hljs-keyword">this</span>.id, name, numb)
    }
```

Now, since we referenced a `ChatRoom` activity earlier in the `onUserClicked` method, let’s create it.

Create a new activity called `ChatRoom`. The activity comes with a layout file `activity_chat_room`, paste this in the layout file:

```
    // File: ./app/src/main/res/layout/activity_chat_room.xml
    <span class="hljs-meta"><?xml version="1.0" encoding="utf-8"?></span>
    <span class="hljs-tag"><<span class="hljs-name">android.support.constraint.ConstraintLayout</span> <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
      <span class="hljs-attr">xmlns:app</span>=<span class="hljs-string">"http://schemas.android.com/apk/res-auto"</span>
      <span class="hljs-attr">xmlns:tools</span>=<span class="hljs-string">"http://schemas.android.com/tools"</span>
      <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
      <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"match_parent"</span>
      <span class="hljs-attr">tools:context</span>=<span class="hljs-string">".ChatRoom"</span>></span>

      <span class="hljs-tag"><<span class="hljs-name">android.support.v7.widget.RecyclerView</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/recyclerViewChat"</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"match_parent"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"match_parent"</span> /></span>

      <span class="hljs-tag"><<span class="hljs-name">EditText</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/editText"</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"0dp"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">android:layout_margin</span>=<span class="hljs-string">"16dp"</span>
        <span class="hljs-attr">android:hint</span>=<span class="hljs-string">"Enter a message"</span>
        <span class="hljs-attr">app:layout_constraintBottom_toBottomOf</span>=<span class="hljs-string">"parent"</span>
        <span class="hljs-attr">app:layout_constraintEnd_toStartOf</span>=<span class="hljs-string">"@+id/sendButton"</span>
        <span class="hljs-attr">app:layout_constraintStart_toStartOf</span>=<span class="hljs-string">"parent"</span> /></span>

      <span class="hljs-tag"><<span class="hljs-name">android.support.design.widget.FloatingActionButton</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/sendButton"</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">android:layout_gravity</span>=<span class="hljs-string">"end|bottom"</span>
        <span class="hljs-attr">android:layout_margin</span>=<span class="hljs-string">"16dp"</span>
        <span class="hljs-attr">android:src</span>=<span class="hljs-string">"@android:drawable/ic_menu_send"</span>
        <span class="hljs-attr">app:layout_constraintEnd_toEndOf</span>=<span class="hljs-string">"parent"</span>
        <span class="hljs-attr">app:layout_constraintBottom_toBottomOf</span>=<span class="hljs-string">"parent"</span> /></span>

    <span class="hljs-tag"></<span class="hljs-name">android.support.constraint.ConstraintLayout</span>></span>
```

The layout above contains a recycler view for the chat messages, an edit text to collect new messages, and a floating action button to send the message.

Next, create a new class called `ChatRoomAdapter` and paste the following:

```
    <span class="hljs-comment">// File: ./app/src/main/java/com/example/messengerapp/ChatRoomAdapter.kt</span>
    <span class="hljs-keyword">import</span> android.support.v7.widget.CardView
    <span class="hljs-keyword">import</span> android.support.v7.widget.RecyclerView
    <span class="hljs-keyword">import</span> android.view.LayoutInflater
    <span class="hljs-keyword">import</span> android.view.View
    <span class="hljs-keyword">import</span> android.view.ViewGroup
    <span class="hljs-keyword">import</span> android.widget.RelativeLayout
    <span class="hljs-keyword">import</span> android.widget.TextView
    <span class="hljs-keyword">import</span> java.util.*

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ChatRoomAdapter</span> </span>(<span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> list: ArrayList<MessageModel>)
      : RecyclerView.Adapter<ChatRoomAdapter.ViewHolder>() {

      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreateViewHolder</span><span class="hljs-params">(parent: <span class="hljs-type">ViewGroup</span>, viewType: <span class="hljs-type">Int</span>)</span></span>: ViewHolder {
        <span class="hljs-keyword">return</span> ViewHolder(LayoutInflater.from(parent.context)
            .inflate(R.layout.chat_item, parent, <span class="hljs-literal">false</span>))
      }

      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onBindViewHolder</span><span class="hljs-params">(holder: <span class="hljs-type">ViewHolder</span>, position: <span class="hljs-type">Int</span>)</span></span> = holder.bind(list[position])

      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">getItemCount</span><span class="hljs-params">()</span></span>: <span class="hljs-built_in">Int</span> = list.size

      <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">add</span><span class="hljs-params">(message: <span class="hljs-type">MessageModel</span>)</span></span> {
        list.add(message)
        notifyDataSetChanged()
      }

      <span class="hljs-keyword">inner</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ViewHolder</span></span>(itemView: View) : RecyclerView.ViewHolder(itemView) {
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> messageTextView: TextView = itemView.findViewById(R.id.text)
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">val</span> cardView: CardView = itemView.findViewById(R.id.cardView)

        <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">bind</span><span class="hljs-params">(message: <span class="hljs-type">MessageModel</span>)</span></span> = with(itemView) {
          messageTextView.text = message.message
          <span class="hljs-keyword">val</span> params = cardView.layoutParams <span class="hljs-keyword">as</span> RelativeLayout.LayoutParams
          <span class="hljs-keyword">if</span> (message.senderId==Singleton.getInstance().currentUser.id) {
            params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
          }
        }
      }
    }
```

This adapter works in a similar fashion as the one we created earlier. One difference though is that the show online and offline methods are not needed here.

Next, create another class named `MessageModel` and paste this:

```
    <span class="hljs-comment">// File: ./app/src/main/java/com/example/messengerapp/MessageModel.kt</span>
    <span class="hljs-keyword">data</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">MessageModel</span></span>(<span class="hljs-keyword">val</span> message: String, <span class="hljs-keyword">val</span> senderId: String)
```

The `chat_item` layout used in the `onCreateViewHolder` method of the adapter class represents how each layout will look like. Create a new layout called `chat_item` and paste this:

```
    // File: ./app/src/main/res/layout/chat_item.xml
    <span class="hljs-meta"><?xml version="1.0" encoding="utf-8"?></span>
    <span class="hljs-tag"><<span class="hljs-name">RelativeLayout</span> <span class="hljs-attr">xmlns:android</span>=<span class="hljs-string">"http://schemas.android.com/apk/res/android"</span>
      <span class="hljs-attr">xmlns:app</span>=<span class="hljs-string">"http://schemas.android.com/apk/res-auto"</span>
      <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"wrap_content"</span>
      <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
      <span class="hljs-attr">android:layout_margin</span>=<span class="hljs-string">"16dp"</span>
      <span class="hljs-attr">android:orientation</span>=<span class="hljs-string">"vertical"</span>></span>

      <span class="hljs-tag"><<span class="hljs-name">android.support.v7.widget.CardView</span>
        <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/cardView"</span>
        <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
        <span class="hljs-attr">android:layout_gravity</span>=<span class="hljs-string">"start"</span>
        <span class="hljs-attr">app:cardCornerRadius</span>=<span class="hljs-string">"8dp"</span>
        <span class="hljs-attr">app:cardUseCompatPadding</span>=<span class="hljs-string">"true"</span>></span>

        <span class="hljs-tag"><<span class="hljs-name">LinearLayout</span>
          <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"wrap_content"</span>
          <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
          <span class="hljs-attr">android:gravity</span>=<span class="hljs-string">"start"</span>
          <span class="hljs-attr">android:orientation</span>=<span class="hljs-string">"vertical"</span>
          <span class="hljs-attr">android:padding</span>=<span class="hljs-string">"8dp"</span>></span>

          <span class="hljs-tag"><<span class="hljs-name">TextView</span>
            <span class="hljs-attr">android:id</span>=<span class="hljs-string">"@+id/text"</span>
            <span class="hljs-attr">android:layout_width</span>=<span class="hljs-string">"wrap_content"</span>
            <span class="hljs-attr">android:layout_height</span>=<span class="hljs-string">"wrap_content"</span>
            <span class="hljs-attr">android:layout_gravity</span>=<span class="hljs-string">"center_vertical|start"</span>
            <span class="hljs-attr">android:layout_marginBottom</span>=<span class="hljs-string">"4dp"</span>
            <span class="hljs-attr">android:textStyle</span>=<span class="hljs-string">"bold"</span> /></span>

        <span class="hljs-tag"></<span class="hljs-name">LinearLayout</span>></span>

      <span class="hljs-tag"></<span class="hljs-name">android.support.v7.widget.CardView</span>></span>

    <span class="hljs-tag"></<span class="hljs-name">RelativeLayout</span>></span>
```

Finally, open the `ChatRoom` activity class and paste this:

```
    <span class="hljs-comment">// File: ./app/src/main/java/com/example/messengerapp/ChatRoom.kt</span>
    <span class="hljs-keyword">import</span> android.app.Activity
    <span class="hljs-keyword">import</span> android.os.Bundle
    <span class="hljs-keyword">import</span> android.support.v7.app.AppCompatActivity
    <span class="hljs-keyword">import</span> android.support.v7.widget.LinearLayoutManager
    <span class="hljs-keyword">import</span> android.util.Log
    <span class="hljs-keyword">import</span> android.view.View
    <span class="hljs-keyword">import</span> android.view.inputmethod.InputMethodManager
    <span class="hljs-keyword">import</span> com.pusher.client.Pusher
    <span class="hljs-keyword">import</span> com.pusher.client.PusherOptions
    <span class="hljs-keyword">import</span> com.pusher.client.channel.PrivateChannelEventListener
    <span class="hljs-keyword">import</span> com.pusher.client.util.HttpAuthorizer
    <span class="hljs-keyword">import</span> kotlinx.android.synthetic.main.activity_chat_room.*
    <span class="hljs-keyword">import</span> okhttp3.MediaType
    <span class="hljs-keyword">import</span> okhttp3.RequestBody
    <span class="hljs-keyword">import</span> org.json.JSONObject
    <span class="hljs-keyword">import</span> retrofit2.Call
    <span class="hljs-keyword">import</span> retrofit2.Callback
    <span class="hljs-keyword">import</span> retrofit2.Response
    <span class="hljs-keyword">import</span> java.lang.Exception
    <span class="hljs-keyword">import</span> java.util.*

    <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ChatRoom</span> : <span class="hljs-type">AppCompatActivity</span></span>() {

      <span class="hljs-keyword">companion</span> <span class="hljs-keyword">object</span> {
        <span class="hljs-keyword">const</span> <span class="hljs-keyword">val</span> EXTRA_ID = <span class="hljs-string">"id"</span>
        <span class="hljs-keyword">const</span> <span class="hljs-keyword">val</span> EXTRA_NAME = <span class="hljs-string">"name"</span>
        <span class="hljs-keyword">const</span> <span class="hljs-keyword">val</span> EXTRA_COUNT = <span class="hljs-string">"numb"</span>
      }

      <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> contactName: String
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> contactId: String
      <span class="hljs-keyword">private</span> <span class="hljs-keyword">var</span> contactNumb: <span class="hljs-built_in">Int</span> = -<span class="hljs-number">1</span>
      <span class="hljs-keyword">lateinit</span> <span class="hljs-keyword">var</span> nameOfChannel: String
      <span class="hljs-keyword">val</span> mAdapter = ChatRoomAdapter(ArrayList())

      <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onCreate</span><span class="hljs-params">(savedInstanceState: <span class="hljs-type">Bundle</span>?)</span></span> {
        <span class="hljs-keyword">super</span>.onCreate(savedInstanceState)
        setContentView(R.layout.activity_chat_room)
        fetchExtras()
        setupRecyclerView()
        subscribeToChannel()
        setupClickListener()
      }
    }
```

In this file, we declared constants used to send data to the activity through intents. We also initialized variables we will use later like the adapter the contact details. We then called some additional methods in the `onCreate` method. Let’s add them to the class.

Add the `fetchExtras` method defined below to the class. The method gets the extras sent from the chatroom activity.

```
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">fetchExtras</span><span class="hljs-params">()</span></span> {
      contactName = intent.extras.getString(ChatRoom.EXTRA_NAME)
      contactId = intent.extras.getString(ChatRoom.EXTRA_ID)
      contactNumb = intent.extras.getInt(ChatRoom.EXTRA_COUNT)
    }
```

The next method is the `setupRecyclerView` method. This initializes the recycler view with an adapter and a layout manager. Paste the function in the same class as before:

```
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setupRecyclerView</span><span class="hljs-params">()</span></span> {
      with(recyclerViewChat) {
        layoutManager = LinearLayoutManager(<span class="hljs-keyword">this</span><span class="hljs-symbol">@ChatRoom</span>)
        adapter = mAdapter
      }
    }
```

The next method is the `subscribeToChannel` method. This method subscribes the user to a private channel with the selected contact. Paste the following code to the same class as before:

```
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">subscribeToChannel</span><span class="hljs-params">()</span></span> {
      <span class="hljs-keyword">val</span> authorizer = HttpAuthorizer(<span class="hljs-string">"http://10.0.2.2:5000/pusher/auth/private"</span>)
      <span class="hljs-keyword">val</span> options = PusherOptions().setAuthorizer(authorizer)
      options.setCluster(<span class="hljs-string">"PUSHER_APP_CLUSTER"</span>)

      <span class="hljs-keyword">val</span> pusher = Pusher(<span class="hljs-string">"PUSHER_APP_KEY"</span>, options)
      pusher.connect()

      nameOfChannel = <span class="hljs-keyword">if</span> (Singleton.getInstance().currentUser.count > contactNumb) {
        <span class="hljs-string">"private-"</span> + Singleton.getInstance().currentUser.id + <span class="hljs-string">"-"</span> + contactId
      } <span class="hljs-keyword">else</span> {
        <span class="hljs-string">"private-"</span> + contactId + <span class="hljs-string">"-"</span> + Singleton.getInstance().currentUser.id
      }

      Log.i(<span class="hljs-string">"ChatRoom"</span>, nameOfChannel)

      pusher.subscribePrivate(nameOfChannel, <span class="hljs-keyword">object</span> : PrivateChannelEventListener {
        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onEvent</span><span class="hljs-params">(channelName: <span class="hljs-type">String</span>?, eventName: <span class="hljs-type">String</span>?, <span class="hljs-keyword">data</span>: <span class="hljs-type">String</span>?)</span></span> {
          <span class="hljs-keyword">val</span> obj = JSONObject(<span class="hljs-keyword">data</span>)
          <span class="hljs-keyword">val</span> messageModel = MessageModel(obj.getString(<span class="hljs-string">"message"</span>), obj.getString(<span class="hljs-string">"sender_id"</span>))

          runOnUiThread {
            mAdapter.add(messageModel)
          }
        }

        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onAuthenticationFailure</span><span class="hljs-params">(p0: <span class="hljs-type">String</span>?, p1: <span class="hljs-type">Exception</span>?)</span></span> {}
        <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onSubscriptionSucceeded</span><span class="hljs-params">(p0: <span class="hljs-type">String</span>?)</span></span> {}
      }, <span class="hljs-string">"new-message"</span>)
    }
```

> Replace the `PUSHER_APP_*` keys with the values on your dashboard.

The code above allows a user to subscribe to a private channel. A private channel requires authorization like the presence channel. However, it does not expose a callback that is triggered when other users subscribe.

Next method to be added is the `setupClickListener`. Paste the method to the same class as before:

```
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">setupClickListener</span><span class="hljs-params">()</span></span> {
      sendButton.setOnClickListener{
        <span class="hljs-keyword">if</span> (editText.text.isNotEmpty()) {
          <span class="hljs-keyword">val</span> jsonObject = JSONObject()
          jsonObject.put(<span class="hljs-string">"message"</span>,editText.text.toString())
          jsonObject.put(<span class="hljs-string">"channel_name"</span>,nameOfChannel)
          jsonObject.put(<span class="hljs-string">"sender_id"</span>,Singleton.getInstance().currentUser.id)

          <span class="hljs-keyword">val</span> jsonBody = RequestBody.create(
              MediaType.parse(<span class="hljs-string">"application/json; charset=utf-8"</span>), 
              jsonObject.toString()
          )

          RetrofitInstance.retrofit.sendMessage(jsonBody).enqueue(<span class="hljs-keyword">object</span>: Callback<String>{
            <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onFailure</span><span class="hljs-params">(call: <span class="hljs-type">Call</span><<span class="hljs-type">String</span>>?, t: <span class="hljs-type">Throwable</span>?)</span></span> {}
            <span class="hljs-keyword">override</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">onResponse</span><span class="hljs-params">(call: <span class="hljs-type">Call</span><<span class="hljs-type">String</span>>?, response: <span class="hljs-type">Response</span><<span class="hljs-type">String</span>>?)</span></span> {}
          })

          editText.text.clear()
          hideKeyBoard()
        }

      }
    }
```

The method above assigns a click listener to the floating action button to send the message to the server. After the message is sent, we clear the text view and hide the keyboard.

Add a method to the same class for hiding the keyboard like this:

```
    <span class="hljs-keyword">private</span> <span class="hljs-function"><span class="hljs-keyword">fun</span> <span class="hljs-title">hideKeyBoard</span><span class="hljs-params">()</span></span> {
      <span class="hljs-keyword">val</span> imm = getSystemService(Activity.INPUT_METHOD_SERVICE) <span class="hljs-keyword">as</span> InputMethodManager
      <span class="hljs-keyword">var</span> view = currentFocus

      <span class="hljs-keyword">if</span> (view == <span class="hljs-literal">null</span>) {
        view = View(<span class="hljs-keyword">this</span>)
      }

      imm.hideSoftInputFromWindow(view.windowToken, <span class="hljs-number">0</span>)
    }
```

That’s all for the application. Now you can run your application in Android Studio and you should see the application in action.

> Make sure the Node.js API we built earlier is running before running the Android application.

![](//images.ctfassets.net/1es3ne0caaid/mmdMFfq7WoYsk26cIKocs/486ce2b458e45a41cfeb01ab4441f3b4/android-messenger-presence-demo.gif)

## Conclusion

In this article, you have been introduced yet again to some Pusher’s capabilities such as the private and presence channel. We learned how to authenticate our users for the various channels. We used these channels to implement a private chat between two persons and an online notification for a contact.

The source code to the application built in this article is available on [GitHub](https://github.com/neoighodaro/kotlin-messenger-app-with-online-presence-status).

This post first appeared on the [Pusher blog](https://pusher.com/tutorials/android-messenger-presence-kotlin).