Android Smack XMPP Introduction:Building a Simple Client

rooster_full_chat_processed

Xmpp is a protocol for Presence and Messaging , and Smack is a Java/android implementation of the protocol that helps developers build fast client applications.When one embarks on the journey to build android chat apps based on xmpp using Smack ,there are a lot of pitfalls one can come across as you are trying to combine the three worlds of Java , Android and the Xmpp protocol itself to build one coherent product.This tutorial aims at documenting these and possible ways to mitigate them.By the end of this tutorial ,you will have an android chat client that can connect to and XMPP server , send and receive messages .Most importantly ,you will learn the android plumbing necessary to get all this rolling.Lets get started.Shall we.


Complete step by step video Course on XMPP and Smack on Android now available. By the Same Author of this Tute.Help spread the news.

XMPP Server Options

You probably know by now that xmpp applications follow the Client Server design architecture.If you don’t ,please have a look at this XMPP introduction guide where I go through the basics of xmpp.In this section we focus on the options available to you when it comes to using an XMPP server.You basically have two choises :

(1) You can use one of the publicly available xmpp servers

There are a good number of publicly available xmpp severs out there that you can just use.They usually provide a web interface that you use to register and when the registration is successful you can use any xmpp client to connect to the server and start exchanging messages .I find this list maintained by the XMPP Standard Foundation pretty handy so I leave it here as a reference.This list available at jabber.at can also prove to be useful.This option is the easiest as you don’t have to worry about the server details and you can fully focus on client development.This is the option we choose in this tutorial.

(2) You can install and maintain your own XMPP server

There are a lot of xmpp server implementations out there both commercial and open source.XMPP.ORG does a good job of maintaining a regularly updated list you can look at.If you are interested in installing ejabberd on your linux platform I have tutorials on how to install both from source code and binary packages.

Building the android User Interface.

The app workflow is simple .When the user starts the app , a login user interface is shown , the user types in the Jabber ID (JID) and the password and signs in.Once in , another piece of ui is shown with a list of contacts.Once you click on one contact ,a chat ui is shown where you can type in and send messages and see messages you receive from the other party.The design looks as shown in the figure below.

Rooster_app_design_processed

The Login Activity

Fire up Android Studio and create a new project.I name mine Rooster ,well because I love roosters and save it in the location of your choice.

android_studio_new_project_processed

Click next and in the following dialog ,choose the minimun sdk .We choose API 16 as it allows us to target a reasonable amount of android devices out there.

rooster_mininum_sdk_processed1

Click next and the next dialog lets you choose the first UI your users see when they start your app.

rooster_login_activity_processed

We obviously choose the Login Activity as it closely matches the design we want to implement by giving us ready to use data input fields and some error checking code as you will see shortly.Click next ,choose the names for your activity and layout files,you can leave in the defaults names.Click finish and see android studio generating your project.The generated project is shown below for reference.

rooster_android_studio_generated_project_processed

The design view of our layout file has almost everything we need in place as shown below.

rooster_login_layout_design_view_processed

We simply need to change the text in those fields to match what we need in Rooster.Email should be changed to Jabber Id ,our password is not optional and finally the button should only say Sign in.You apply these changes in the strings.xml file located in the res/values/ folder of your resource files as shown below.

rooster_edit_strings_file_processed

Another useful thing to do now is to rename the names for our strings.The string “prompt_email” should be renamed “prompt_jid”. Other relevant strings should follow the same logic.In android studio there is a way to do that really fast.Click on the string you wish to edit and right click.In the context menu that shows up click Refactor and then rename as shown below.

rooster_strings_rename_processed

Click refactor and the string name is updated throughout your entire project.Repeat the same process for “error_invalid_email” and rename it “error_invalid_jid”. The layout for our project is ready.Run the app on a virtual device( or a real device if you choose so) and you will see the login interface as shown below.

rooster_login_ui_processed

You can see that our updates strings have taken effect.Also notice that when we typed in a wrong JID ( a valid jid should be of the form user@server.com) ,the ui shows a friendly message saying that our jid is invalid.This error checking mechanism is controlled in LoginActivity.java that we are exploring next.

LoginActivity.java implements the logic behind our layout design.It is the brains of our activity.In the particular case or Rooster ,its most important responsibility is to fire up the login mechanism.On top of that ,it performs error checking on the data input by the user.But before we see how that happens ,we need to do some clean up.

Right now ,LoginActivity.java is trying to do two things we don’t need.One is doing email autocomplete as the user types in ,and the other is trying to simulate the login logic.These are great when you need them but for now ,… thanks Android Studio ,we are getting read of all the code that does that.The updated LoginActivity.java code is shown below for reference.

package com.blikoon.rooster;

import android.animation.Animator;


import static android.Manifest.permission.READ_CONTACTS;

/**
 * A login screen that offers login via jid/password.
 */
public class LoginActivity extends AppCompatActivity
{
    /**
     * Id to identity READ_CONTACTS permission request.
     */
    private static final int REQUEST_READ_CONTACTS = 0;
    

    // UI references.
    private AutoCompleteTextView mJidView;
    private EditText mPasswordView;
    private View mProgressView;
    private View mLoginFormView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);
        // Set up the login form.
        mJidView = (AutoCompleteTextView) findViewById(R.id.email);
        populateAutoComplete();

        mPasswordView = (EditText) findViewById(R.id.password);
        mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
                if (id == R.id.login || id == EditorInfo.IME_NULL) {
                    attemptLogin();
                    return true;
                }
                return false;
            }
        });

        Button mJidSignInButton = (Button) findViewById(R.id.email_sign_in_button);
        mJidSignInButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                attemptLogin();
            }
        });

        mLoginFormView = findViewById(R.id.login_form);
        mProgressView = findViewById(R.id.login_progress);
    }

    private void populateAutoComplete() {
        if (!mayRequestContacts()) {
            return;
        }

        //getLoaderManager().initLoader(0, null, this);
    }

    private boolean mayRequestContacts() {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return true;
        }
        if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
            return true;
        }
        if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
            Snackbar.make(mJidView, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
                    .setAction(android.R.string.ok, new View.OnClickListener() {
                        @Override
                        @TargetApi(Build.VERSION_CODES.M)
                        public void onClick(View v) {
                            requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
                        }
                    });
        } else {
            requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
        }
        return false;
    }

    /**
     * Callback received when a permissions request has been completed.
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        if (requestCode == REQUEST_READ_CONTACTS) {
            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                populateAutoComplete();
            }
        }
    }


    /**
     * Attempts to sign in or register the account specified by the login form.
     * If there are form errors (invalid email, missing fields, etc.), the
     * errors are presented and no actual login attempt is made.
     */
    private void attemptLogin() {
        // Reset errors.
        mJidView.setError(null);
        mPasswordView.setError(null);

        // Store values at the time of the login attempt.
        String email = mJidView.getText().toString();
        String password = mPasswordView.getText().toString();

        boolean cancel = false;
        View focusView = null;

        // Check for a valid password, if the user entered one.
        if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
            mPasswordView.setError(getString(R.string.error_invalid_password));
            focusView = mPasswordView;
            cancel = true;
        }

        // Check for a valid email address.
        if (TextUtils.isEmpty(email)) {
            mJidView.setError(getString(R.string.error_field_required));
            focusView = mJidView;
            cancel = true;
        } else if (!isEmailValid(email)) {
            mJidView.setError(getString(R.string.error_invalid_jid));
            focusView = mJidView;
            cancel = true;
        }

        if (cancel) {
            // There was an error; don't attempt login and focus the first
            // form field with an error.
            focusView.requestFocus();
        } else {
            // Show a progress spinner, and kick off a background task to
            // perform the user login attempt.
            showProgress(true);
            //This is where the login login is fired up.

        }
    }

    private boolean isEmailValid(String email) {
        //TODO: Replace this with your own logic
        return email.contains("@");
    }

    private boolean isPasswordValid(String password) {
        //TODO: Replace this with your own logic
        return password.length() > 4;
    }

    /**
     * Shows the progress UI and hides the login form.
     */
    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
    private void showProgress(final boolean show) {
        // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
        // for very easy animations. If available, use these APIs to fade-in
        // the progress spinner.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);

            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
            mLoginFormView.animate().setDuration(shortAnimTime).alpha(
                    show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
                }
            });

            mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
            mProgressView.animate().setDuration(shortAnimTime).alpha(
                    show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
                }
            });
        } else {
            // The ViewPropertyAnimator APIs are not available, so simply show
            // and hide the relevant UI components.
            mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
        }
    }
}

In the onCreate override method ,we setup our activity to use the activity_login.xml layout file,get reference to the UI components ,namely the Jid field ,the password field and the Sign in Button.We set a click listener to the Button and when the button is clicked ,we call the attemptLogin() method.

This function first checks to see that the jid and the password are valid.A jid is valid if it contains one “@” character and passwords of more than four characters are supported.This is a simple policy that comes by default with the code that Android Studio has generated for us.We leave it that way for this tutorial.

Just to check that our code is working as expected lets add a simple log statement inside the attemptLogin() method that gets executed when the jid and password typed in by the user are all valid.

private void attemptLogin() {
       ...

    if (cancel) {
        // There was an error; don't attempt login and focus the first
        // form field with an error.
        focusView.requestFocus();
    } else {
        showProgress(true);
        //This is where the login login is fired up.
        Log.d(TAG,"Jid and password are valid ,proceeding with login.");

    }
}

If we run the app ,we can see the debug output when the user has input a valid jid like user@server.com and a password of at least five characters.

rooster_login_log_outupt_prefered

In the left side of the figure ,you can see the spinning wheel that signals to the user that something is going on.At this point ,we are done with the login ui.

The Contact List Activity.

Add a new activity to your project and name it ContactListActivity as shown below.

roster_create_contact_list_activity_processed

Click finish and your activity is created.This activity will use an implementation of List View android provides called RecyclerView.We won’t go into the details of how RecyclerViews work ,if you find them confusing somehow ,please check out a previous tutorial of mine that goes into the details of how it works.

Before using the RecyclerView ,you need to add it as a dependancy to your project.To load it hit File->Project Structure.The Project Structure dialog comes up as shown below.

android_project_structure_1

Choose app in the left pane ,click on the green plus button ,in the dialog that pops up ,scoll down until you see a line containing recyclerview-v7 as shown below.

android_recyclerview_dependency

Hit the OK button twice and Android should load your library in a few seconds.

Modify your activity_contact_list.xml file to add a recyclerView as follows.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.blikoon.rooster.ContactListActivity">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/contact_list_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </android.support.v7.widget.RecyclerView>

</RelativeLayout>

Our Recycler view will need a model to operate on ,we add two Java classes to take care of that : Contact and ContactModel.

Contact.java

package com.blikoon.rooster;

/**
 * Created by gakwaya on 4/16/2016.
 */
public class Contact {
    private String jid;
  
    public Contact(String contactJid )
    {
        jid = contactJid;
    }
    
    public String getJid()
    {
        return jid;
    }

    public void setJid(String jid) {
        this.jid = jid;
    }
}

The class is very simple.It only has only one member variable to store the contact jid.Other variables may be added later as need arises.

ContactModel.java

package com.blikoon.rooster;

import android.content.Context;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by gakwaya on 4/16/2016.
 */
public class ContactModel {

    private static ContactModel sContactModel;
    private List<Contact> mContacts;

    public static ContactModel get(Context context)
    {
        if(sContactModel == null)
        {
            sContactModel = new ContactModel(context);
        }
        return  sContactModel;
    }

    private ContactModel(Context context)
    {
        mContacts = new ArrayList<>();
        populateWithInitialContacts(context);

    }

    private void populateWithInitialContacts(Context context)
    {
        //Create the Foods and add them to the list;

      
        Contact contact1 = new Contact("User1@server.com");
        mContacts.add(contact1);
        Contact contact2 = new Contact("User2@server.com");
        mContacts.add(contact2);
        Contact contact3 = new Contact("User3@server.com");
        mContacts.add(contact3);
        Contact contact4 = new Contact("User4@server.com");
        mContacts.add(contact4);
        Contact contact5 = new Contact("User5@server.com");
        mContacts.add(contact5);
        Contact contact6 = new Contact("User6@server.com");
        mContacts.add(contact6);
        Contact contact7 = new Contact("User7@server.com");
        mContacts.add(contact7);
    }

    public List<Contact> getContacts()
    {
        return mContacts;
    }

}

ContactModel implements the singleton .Our application only needs one instance of this class as it will work on the same contact data set.With our model in place ,we can now set up a ViewHolder and an Adapter inside the ContactListActivity class.But before we do that we need to define how every single contact item is going to look in the list view.Add a new layout file in the /res/layout folder and name it list_item_contact and make sure its contents are as follows.

list_item_contact.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:id="@+id/contact_jid"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="user@example.com"
        android:textSize="35dp"/>


</LinearLayout>

Next we add a ContactHolder inner class to ContactListActivity as shown below.

public class ContactListActivity extends AppCompatActivity {

    private static final String TAG = "ContactListActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_contact_list);
    }



    private class ContactHolder extends RecyclerView.ViewHolder
    {
        private TextView contactTextView;
        private Contact mContact;
        public ContactHolder ( View itemView)
        {
            super(itemView);

            contactTextView = (TextView) itemView.findViewById(R.id.contact_jid);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    //Inside here we start the chat activity

                }
            });
        }


        public void bindContact( Contact contact)
        {
            mContact = contact;
            if (mContact == null)
            {
                Log.d(TAG,"Trying to work on a null Contact object ,returning.");
                return;
            }
            contactTextView.setText(mContact.getJid());

        }
    }
}

ContactHolder embodies the looks of each Contact item in the list of Contacts that RecyclerView contains.It also provides a public method that the adapter is going to use to set the text shown in each item.We add the adapter class next.ContactAdapter is also added as an inner class as shown below.

private class ContactAdapter extends RecyclerView.Adapter<ContactHolder>
{
    private List<Contact> mContacts;

    public ContactAdapter( List<Contact> contactList)
    {
        mContacts = contactList;
    }

    @Override
    public ContactHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
        View view = layoutInflater
                .inflate(R.layout.list_item_contact, parent,
                        false);
        return new ContactHolder(view);
    }

    @Override
    public void onBindViewHolder(ContactHolder holder, int position) {
        Contact contact = mContacts.get(position);
        holder.bindContact(contact);

    }

    @Override
    public int getItemCount() {
        return mContacts.size();
    }
}

It overrides the three methods a RecyclerView’s adapter needs to operate properly.For more on these methods please check the tutorial specific to the RecyclerView.With the ViewHolder and the Adapter in place ,we can add final touches to our ContactListActivity by defining its RecyclerView , defining the data model and applying it to the adapter and finaly let the RecyclerView use our adapter.The details are shown below.

ContactListActivity.java

package com.blikoon.rooster;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;

public class ContactListActivity extends AppCompatActivity {

    private static final String TAG = "ContactListActivity";

    private RecyclerView contactsRecyclerView;
    private ContactAdapter mAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_contact_list);

        contactsRecyclerView = (RecyclerView) findViewById(R.id.contact_list_recycler_view);
        contactsRecyclerView.setLayoutManager(new LinearLayoutManager(getBaseContext()));

        ContactModel model = ContactModel.get(getBaseContext());
        List<Contact> contacts = model.getContacts();

        mAdapter = new ContactAdapter(contacts);
        contactsRecyclerView.setAdapter(mAdapter);
    }



    private class ContactHolder extends RecyclerView.ViewHolder
    {
       ...
    }


    private class ContactAdapter extends RecyclerView.Adapter<ContactHolder>
    {
       ...
    }
}

How do we test that ContactListActivity is working correctly?For now we can start it when the user clicks on the SignIn button from LoginActivity.Change your attemptLogin() method as follows.

private void attemptLogin() {
    ...

    if (cancel) {
        // There was an error; don't attempt login and focus the first
        // form field with an error.
        focusView.requestFocus();
    } else {
        // Show a progress spinner, and kick off a background task to
        // perform the user login attempt.
        //showProgress(true);<<---FOR NOW WE DON'T WANT TO SEE THIS PROGRESS THING.
        //This is where the login login is fired up.
        Log.d(TAG,"Jid and password are valid ,proceeding with login.");
        startActivity(new Intent(this,ContactListActivity.class));

    }
}

Run the app ,type in a jid and a password and hit login .Our shiny ContactListActivity should show up as shown below.

rooster_contact_list_activity_test_processed

yes the list looks like it could use some spacing but that’s an easy fix by specifying some reasonable height for the TextView inside the list_item_contact.xml layout file.

Building the ChatActivity.

Building a good looking chat activity is a bit involved.Luckily somebody has already done the heavy lifting for us and we are just going to build on top of their work.Add a new activity to the project and name it ChatActivity.  The library in this github repo provides a good library we can use to build our chat activity.Just follow the instructions they give on how to use it.Add

implementation 'com.github.timigod:android-chat-ui:v0.1.3'

to your build.gradle file (Module:app) as shown below and sync the project.

The “ext” block allows us to control the versions of the libraries we import in one place.After your project finishes syncing ,you can now use the components from the library, we define the supportLibVersion variable which is used down in the dependencies block.The android-chat-ui library is going to give us a ready to use Chat Activity.Modify the activity_chat.xml layout file as shown below to add a ChatView to ChatActivity.

activity_chat.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.blikoon.rooster.ChatActivity">

    <co.devcenter.androiduilibrary.ChatView
        android:id="@+id/rooster_chat_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    </co.devcenter.androiduilibrary.ChatView>

</RelativeLayout>

At this moment ,you can see your ChatActivity and interact with it in the app.To see it in action ,we are going to start the ChatActivity whenever a user presses any item in ContactListActivity.ContactListActivity will also pass along the Jid of the item that has been clicked.Modify the clickListener of ContactHolder inside ContactListActivity as shown below.

private class ContactHolder extends RecyclerView.ViewHolder
{
    private TextView contactTextView;
    private Contact mContact;
    public ContactHolder ( View itemView)
    {
        super(itemView);

        contactTextView = (TextView) itemView.findViewById(R.id.contact_jid);

        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Inside here we start the chat activity
                Intent intent = new Intent(ContactListActivity.this
                        ,ChatActivity.class);
                intent.putExtra("EXTRA_CONTACT_JID",mContact.getJid());
                startActivity(intent);


            }
        });
    }


   .....
}

We pass the current item’s Jid to ChatActivity as an intent extra.We also take this chance to modify the list_item_contact.xml layout file so there is some breathing room between items.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:id="@+id/contact_jid"
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:gravity="center"
        android:text="user@example.com"
        android:textSize="35dp"/>

</LinearLayout>

Finally ,modify ChatActivity so it retrieves the current contact jid and shows it as the title label of the activity.

package com.blikoon.rooster;

public class ChatActivity extends AppCompatActivity {
    private ChatView mChatView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);
        mChatView =(ChatView) findViewById(R.id.rooster_chat_view);

        Intent intent = getIntent();
        String contactJid = intent.getStringExtra("EXTRA_CONTACT_JID");
        setTitle(contactJid);
    }
}

Run the app ,click on one item and you should see your ChatActivity as shown below.

rooster_chat_activity_preview_processed

The label is showing the current contact’s jid and right at the bottom you can see the text field where the user types in the message and the blue send button at the bottom right.The ChatActivity is not doing anything interesting for the moment but as shown at the librarie’s github page it can be customized to do more stuff like showing messages you send and receive and responding to the send button click.We will be using these when we start messing around with Smack to send and receive XMPP messages.Our UI work is done for now.Next we’ll see how to get our shiny Rooster to connect to an XMPP server.

Connecting to the XMPP Server.

Adding Smack dependencies to your Android Studio project.

To be able to use Smack in our project ,we need to import it in our android studio project.To do that you add the following lines of code to the build.gradle file of your app module as shown in the figure below. The “ext” block allows us to have the Smack Version defined in one place and for it to be picked up wherever it is needed. We import mack-tcp, smack-experimental and smack-android as shown in the lower section of the image below.

With this in place you can start importing smack classes and using them.But before we do that ,we need to understand something important about how android works.

A word about android Threads and Services.

In android ,it is recommended to run all your networking code in background threads.This is because such long running operations can cause your UI to freeze or even worse ,show a message like “Rooster is not responding do you want to close it?”. You have seen one of these right?So we need our code that connects to and XMPP Server to run in a background thread.

Another thing we want is for our app to stick around even the user navigates away from it so when messages come in we can notify the user by a beep sound , a notification or whatever you see fit.For that to happen the code needs to run inside a Service.You can think of a service like a wrapper that contains code that keeps running even if the activity that started it dies and disappears.But Services run on the UI thread by default ; so to get the behavior we want for our app ,XMPP connection code has to live inside a background thread that is hosted by a Service.The structure of our code can be summarized in the figure shown below.

rooster_connection_thread_service_model_processed

Now we can get back to the real business .Add a new class to your project and name it RoosterConnectionService.You guessed it ,we are creating the service first.Add in the code as shown below.

RoosterConnectionService.java

package com.blikoon.rooster;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.util.Log;

/**
 * Created by gakwaya on 4/28/2016.
 */
public class RoosterConnectionService extends Service {
    private static final String TAG ="RoosterService";
    private boolean mActive;//Stores whether or not the thread is active
    private Thread mThread;
    private Handler mTHandler;//We use this handler to post messages to
    //the background thread.
    
    public RoosterConnectionService() {

    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG,"onCreate()");
    }


    public void start()
    {
        Log.d(TAG," Service Start() function called.");
        if(!mActive)
        {
            mActive = true;
            if( mThread ==null || !mThread.isAlive())
            {
                mThread = new Thread(new Runnable() {
                    @Override
                    public void run() {

                        Looper.prepare();
                        mTHandler = new Handler();
                        //initConnection();
                        //THE CODE HERE RUNS IN A BACKGROUND THREAD.
                        Looper.loop();

                    }
                });
                mThread.start();
            }


        }


    }

    public void stop()
    {
        Log.d(TAG,"stop()");
        mActive = false;
        mTHandler.post(new Runnable() {
            @Override
            public void run() {
                if( mConnection != null)
                  //CODE HERE IS MEANT TO SHUT DOWN OUR CONNECTION TO THE SERVER.
            }
        });

    }

    
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG,"onStartCommand()");
        start();
        return Service.START_STICKY;
        //RETURNING START_STICKY CAUSES OUR CODE TO STICK AROUND WHEN THE APP ACTIVITY HAS DIED.
    }

    @Override
    public void onDestroy() {
        Log.d(TAG,"onDestroy()");
        super.onDestroy();
        stop();
    }
}

In android when you start a service , its onStartCommand override function is called.Inside our onStartCommand() function we initialize our mThread variable and pass it a Runnable whose run() method will contain the code that runs in the background thread.I want you to pay particular attention to the code snippet below if you still find this confusing.

mThread = new Thread(new Runnable() {
    @Override
    public void run() {

        Looper.prepare();
        mTHandler = new Handler();
        //initConnection();
        //THE CODE HERE RUNS IN A BACKGROUND THREAD.
        Looper.loop();

    }
});
mThread.start();

Every thread in android has something called a Looper that keeps looping around waiting for things to happen.It is called an event loop in some other technologies.Lopper.prepare() and Looper.loop() are kind of making sure we have that kind of thing.You can read more about these methods in android docs .The code that we want to run in the background thread has to live between these two function calls.

When you want to tell a thread to do something from another thread ,you use a thing called a Handler.For every thread corresponds one handler.The handler operates on the thread it was defined into.For exmple mTHandler was defined inside mThread ,so it can be used to pass work to mThread.After we setup the thread it is started.

Another thing you should notice is that onStartCommand returns START_STICKY.This effectively tells our service to run forever until someone or something explicitly stops it.

Next ,we layout the details of how we connect to an XMPP Server.Add a new class to your project and name it RoosterConnection.The initial code of the class is shown below.

RoosterConnection.java

package com.blikoon.rooster;

import android.content.Context;
import android.preference.PreferenceManager;
import android.util.Log;

import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.ReconnectionManager;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;

import java.io.IOException;

/**
 * Created by gakwaya on 4/28/2016.
 */
public class RoosterConnection implements ConnectionListener {

    private static final String TAG = "RoosterConnection";

    private  final Context mApplicationContext;
    private  final String mUsername;
    private  final String mPassword;
    private  final String mServiceName;
    private XMPPTCPConnection mConnection;


    public static enum ConnectionState
    {
        CONNECTED ,AUTHENTICATED, CONNECTING ,DISCONNECTING ,DISCONNECTED;
    }

    public static enum LoggedInState
    {
        LOGGED_IN , LOGGED_OUT;
    }


    public RoosterConnection( Context context)
    {
        Log.d(TAG,"RoosterConnection Constructor called.");
        mApplicationContext = context.getApplicationContext();
        String jid = PreferenceManager.getDefaultSharedPreferences(mApplicationContext)
                .getString("xmpp_jid",null);
        mPassword = PreferenceManager.getDefaultSharedPreferences(mApplicationContext)
                .getString("xmpp_password",null);

        if( jid != null)
        {
            mUsername = jid.split("@")[0];
            mServiceName = jid.split("@")[1];
        }else
        {
            mUsername ="";
            mServiceName="";
        }
    }


    public void connect() throws IOException,XMPPException,SmackException
    {
        Log.d(TAG, "Connecting to server " + mServiceName);
        XMPPTCPConnectionConfiguration.XMPPTCPConnectionConfigurationBuilder builder=
                XMPPTCPConnectionConfiguration.builder();
        builder.setServiceName(mServiceName);
        builder.setUsernameAndPassword(mUsername, mPassword);
        builder.setRosterLoadedAtLogin(true);
        builder.setResource("Rooster");

        //Set up the ui thread broadcast message receiver.
        //setupUiThreadBroadCastMessageReceiver();

        mConnection = new XMPPTCPConnection(builder.build());
        mConnection.addConnectionListener(this);
        mConnection.connect();
        mConnection.login();

        ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(mConnection);
        reconnectionManager.setEnabledPerDefault(true);
        reconnectionManager.enableAutomaticReconnection();

    }



    public void disconnect()
    {
        Log.d(TAG,"Disconnecting from serser "+ mServiceName);
        try
        {
            if (mConnection != null)
            {
                mConnection.disconnect();
            }

        }catch (SmackException.NotConnectedException e)
        {
            RoosterConnectionService.sConnectionState=ConnectionState.DISCONNECTED;
            e.printStackTrace();

        }
        mConnection = null;


    }


    @Override
    public void connected(XMPPConnection connection) {
        RoosterConnectionService.sConnectionState=ConnectionState.CONNECTED;
        Log.d(TAG,"Connected Successfully");
    }

    @Override
    public void authenticated(XMPPConnection connection) {
        RoosterConnectionService.sConnectionState=ConnectionState.CONNECTED;
        Log.d(TAG,"Authenticated Successfully");

    }

    @Override
    public void connectionClosed() {
        RoosterConnectionService.sConnectionState=ConnectionState.DISCONNECTED;
        Log.d(TAG,"Connectionclosed()");

    }

    @Override
    public void connectionClosedOnError(Exception e) {
        RoosterConnectionService.sConnectionState=ConnectionState.DISCONNECTED;
        Log.d(TAG,"ConnectionClosedOnError, error "+ e.toString());

    }

    @Override
    public void reconnectingIn(int seconds) {
        RoosterConnectionService.sConnectionState = ConnectionState.CONNECTING;
        Log.d(TAG,"ReconnectingIn() ");

    }

    @Override
    public void reconnectionSuccessful() {
        RoosterConnectionService.sConnectionState = ConnectionState.CONNECTED;
        Log.d(TAG,"ReconnectionSuccessful()");

    }

    @Override
    public void reconnectionFailed(Exception e) {
        RoosterConnectionService.sConnectionState = ConnectionState.DISCONNECTED;
        Log.d(TAG,"ReconnectionFailed()");

    }
}

The class implements the ConnectionListener interface to allow us to listen in on the connection status events.We override the event status methods reproduced below for convenience.

@Override
    //CALLED WHEN WE ARE SUCCESSFULY CONNECTED TO THE SERVER.
    public void connected(XMPPConnection connection) {
        RoosterConnectionService.sConnectionState=ConnectionState.CONNECTED;
        Log.d(TAG,"Connected Successfully");
    }

    @Override
    //CALLED WHEN WE ARE SUCCESSFULY AUTHENTICATED WITH THE SERVER
    public void authenticated(XMPPConnection connection) {
        RoosterConnectionService.sConnectionState=ConnectionState.CONNECTED;
        Log.d(TAG,"Authenticated Successfully");

    }

    @Override
    //CALLED WHEN THE CONNECTION IS CLOSED FOR SOME REASON
    public void connectionClosed() {
        RoosterConnectionService.sConnectionState=ConnectionState.DISCONNECTED;
        Log.d(TAG,"Connectionclosed()");

    }

    @Override
    //CALLED WHEN THE CONNECTION IS CLOSED AS A RESULT OF SOME ERROR.
    public void connectionClosedOnError(Exception e) {
        RoosterConnectionService.sConnectionState=ConnectionState.DISCONNECTED;
        Log.d(TAG,"ConnectionClosedOnError, error "+ e.toString());

    }

    @Override
    //CALLED WHEN THE APP IS TRYING TO RECONNECT 
    public void reconnectingIn(int seconds) {
        RoosterConnectionService.sConnectionState = ConnectionState.CONNECTING;
        Log.d(TAG,"ReconnectingIn() ");

    }

    @Override
    //CALLED WHEN THE APP SUCCESSFULLY RECONNECTS TO THE SERVER
    public void reconnectionSuccessful() {
        RoosterConnectionService.sConnectionState = ConnectionState.CONNECTED;
        Log.d(TAG,"ReconnectionSuccessful()");

    }

    @Override
    //CALLED WHEN RECONNECTION HAS FAILED.
    public void reconnectionFailed(Exception e) {
        RoosterConnectionService.sConnectionState = ConnectionState.DISCONNECTED;
        Log.d(TAG,"ReconnectionFailed()");

    }

You respond to these events inside these methods.In our case we simply set the connection status.Besides these override methods ,we also have a constructor method that simply retrieves the jid and password from Shared Preferences.

The connect() method handles all the heavy lifting to connect to the server.

public void connect() throws IOException,XMPPException,SmackException
{
    Log.d(TAG, "Connecting to server " + mServiceName);
    XMPPTCPConnectionConfiguration.XMPPTCPConnectionConfigurationBuilder builder=
            XMPPTCPConnectionConfiguration.builder();
    builder.setServiceName(mServiceName);
    builder.setUsernameAndPassword(mUsername, mPassword);
    builder.setRosterLoadedAtLogin(true);
    builder.setResource("Rooster");

    //Set up the ui thread broadcast message receiver.
    //setupUiThreadBroadCastMessageReceiver();

    mConnection = new XMPPTCPConnection(builder.build());
    mConnection.addConnectionListener(this);
    mConnection.connect();
    mConnection.login();

    ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(mConnection);
    reconnectionManager.setEnabledPerDefault(true);
    reconnectionManager.enableAutomaticReconnection();

}

XMPPTCPConnectionConfiguration helps wrap the connection data into one object.In our case it stores the username ,the password ,the server domain and resource of the XMPP client.We also use it to specify that the roster is loaded at login( ignore this if you don’t know what a roster is).

We then initialise our XMPPTCPConnection object passing in the configuration .We setup its ConnectionListener ,connect and login into the server.The disonnect method simply …disconnects from the server

public void disconnect()
    {
        Log.d(TAG,"Disconnecting from serser "+ mServiceName);
        try
        {
            if (mConnection != null)
            {
                mConnection.disconnect();
            }

        }catch (SmackException.NotConnectedException e)
        {
            RoosterConnectionService.sConnectionState=ConnectionState.DISCONNECTED;
            e.printStackTrace();

        }
        mConnection = null;


    }

Now we need to modify our RoosterConnectionService class to use the RoosterConnection class to connect to the server.The changes are highlighted below.

RoosterConnectionService.java

package com.blikoon.rooster;


 
public class RoosterConnectionService extends Service {
    private static final String TAG ="RoosterService";

    public static RoosterConnection.ConnectionState sConnectionState;
    public static RoosterConnection.LoggedInState sLoggedInState;
    private boolean mActive;//Stores whether or not the thread is active
    private Thread mThread;
    private Handler mTHandler;//We use this handler to post messages to
    //the background thread.
    private RoosterConnection mConnection;

    public RoosterConnectionService() {

    }
    public static RoosterConnection.ConnectionState getState()
    {
        if (sConnectionState == null)
        {
            return RoosterConnection.ConnectionState.DISCONNECTED;
        }
        return sConnectionState;
    }

    public static RoosterConnection.LoggedInState getLoggedInState()
    {
        if (sLoggedInState == null)
        {
            return RoosterConnection.LoggedInState.LOGGED_OUT;
        }
        return sLoggedInState;
    }

   ...

    private void initConnection()
    {
        Log.d(TAG,"initConnection()");
        if( mConnection == null)
        {
            mConnection = new RoosterConnection(this);
        }
        try
        {
            mConnection.connect();

        }catch (IOException |SmackException |XMPPException e)
        {
            Log.d(TAG,"Something went wrong while connecting ,make sure the credentials are right and try again");
            e.printStackTrace();
            //Stop the service all together.
            stopSelf();
        }

    }


    public void start()
    {
        Log.d(TAG," Service Start() function called.");
        if(!mActive)
        {
            mActive = true;
            if( mThread ==null || !mThread.isAlive())
            {
                mThread = new Thread(new Runnable() {
                    @Override
                    public void run() {

                        Looper.prepare();
                        mTHandler = new Handler();
                        initConnection();
                        //THE CODE HERE RUNS IN A BACKGROUND THREAD.
                        Looper.loop();

                    }
                });
                mThread.start();
            }


        }

    }

    public void stop()
    {
        Log.d(TAG,"stop()");
        mActive = false;
        mTHandler.post(new Runnable() {
            @Override
            public void run() {
                if( mConnection != null)
                {
                    mConnection.disconnect();
                }
            }
        });

    }
     ...
}

We added asConnectionState and sLoggedInState static variables that we will use to track down the connection state and their respective getter functions.Also we add a RoosterConnection object that is initialized in a new added function called initConnection().The function simply calls connect() on the RoosterConnection object.

Inside the start() method ,we simply call initConnection() to connect to the server.Notice that RoosterConnection is initialized inside the background thread that is hosted inside a service.This means that everything that RoosterConnection does happens of the android UI thread and once the service has started ,closing the app by hitting the back button or whatever is not going to interrupt its operation.Also notice that we call disconnect in the stop() method.

We can now put finishing touches to the LoginActivity class and the androidManifest.xml file of our project and see our Rooster app connect to an xmpp server for the first time!In LoginActivity class and the following function to read data from the input fields ,save the data in Shared Preferences and fire up the actual login process.

private void saveCredentialsAndLogin()
{
    Log.d(TAG,"saveCredentialsAndLogin() called.");
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    prefs.edit()
            .putString("xmpp_jid", mJidView.getText().toString())
            .putString("xmpp_password", mPasswordView.getText().toString())
            .putBoolean("xmpp_logged_in",true)
            .commit();

    //Start the service
    Intent i1 = new Intent(this,RoosterConnectionService.class);
    startService(i1);

}

As you can see the login process is started by calling startService with an intent that wraps around the RoosterConnectionService class.This causes RoosterConnectionService.onStartCommand() to be called,the method calls RoosterConnectionService.start() wich in turn creates our RoosterConnection object on a background thread and calls its connect() method.

Modify your LoginActivity.attemptLogin() method to actually call saveCredentialsAndLogin() when the user clicks on the Sign in button.

private void attemptLogin() {

        // Reset errors.
        mJidView.setError(null);
        mPasswordView.setError(null);

        // Store values at the time of the login attempt.
        String email = mJidView.getText().toString();
        String password = mPasswordView.getText().toString();

        boolean cancel = false;
        View focusView = null;

        // Check for a valid password, if the user entered one.
        if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
            mPasswordView.setError(getString(R.string.error_invalid_password));
            focusView = mPasswordView;
            cancel = true;
        }

        // Check for a valid email address.
        if (TextUtils.isEmpty(email)) {
            mJidView.setError(getString(R.string.error_field_required));
            focusView = mJidView;
            cancel = true;
        } else if (!isEmailValid(email)) {
            mJidView.setError(getString(R.string.error_invalid_jid));
            focusView = mJidView;
            cancel = true;
        }

        if (cancel) {
            // There was an error; don't attempt login and focus the first
            // form field with an error.
            focusView.requestFocus();
        } else {
            // Show a progress spinner, and kick off a background task to
            // perform the user login attempt.
            //showProgress(true);
            //This is where the login login is fired up.
//            Log.d(TAG,"Jid and password are valid ,proceeding with login.");
//            startActivity(new Intent(this,ContactListActivity.class));

            //Save the credentials and login
            saveCredentialsAndLogin();

        }
    }

If you run the app now and try to login nothing will happen.This is because we didn’t declare our RoosterConnectionService in the androidManifest.xml file.We also need to add the permission to use the internet.All this is taken care of by modifying the androidManifest.xml file as shown below.

<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.blikoon.rooster"
          xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.INTERNET"/>
    <!-- To auto-complete the email text field in the login form with the user's emails -->
    <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
    <uses-permission android:name="android.permission.READ_PROFILE"/>
    <uses-permission android:name="android.permission.READ_CONTACTS"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".LoginActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name=".ContactListActivity">
        </activity>
        <activity android:name=".ChatActivity">
        </activity>
        <service android:name=".RoosterConnectionService">

        </service>

    </application>

</manifest>

Run the app and if everything is setup as it should ,you’ll see the login screen.Type in your Jid and password.You must have an account on some XMPP server to be able to try this.My login screen looks as shown below.

rooster_login_test_processed

Hit Sign in and watch your debug .You can see below that the debug output of RoosterConnection.connect() is shown and that we both connect and authenticate successfully.

rooster_connected_output_message_processed

If you have trouble seeing this debug output it might help to set up a filter so that output from your package is shown.In the filter combobox on the bottom left of Android Studio,choose Edit Filter Configuration and type in the package you want to filter for ,mine is com.blikoon.rooster as shown below .Type in one that matches your project and try again.

rooster_debug_filter_processed

Showing the ContactListActivity when the user is authenticated.

I agree that just seeing debug output when we get connected isn’t that exciting.We need to show the ContactListActivity so the user can actually start sending and receiving messages.But we can’t just create and intent that starts ContactListActivity inside the authenticated() override method of RoosterConnection.Why?Because everything RoosterConnection does lives in a background thread and we can’t start activities or more generally do anything related to the User Interface inside a background thread.Android forbids it and if you do it you will get nasty errors.

There are many ways to deal with this problem and sending and receiving broadcasts is one of them.Broadcasts are mechanism android provides to send messages that are only received by individuals who have explicitly stated that they are interested in those messages.LoginActivity is going to state that it is interested in specific messages sent by RoosterConnection and RoosterConnection is going to send one of such message when the user is successfully authenticated.

When LoginActivity receives the message it can then start ContactListActivity.Since both Activities live on the UI thread ,everything goes flawlessly.First we define the specific message in RoosterConnectionService as shown below.

public class RoosterConnectionService extends Service {
    private static final String TAG ="RoosterService";
    public static final String UI_AUTHENTICATED = "com.blikoon.rooster.uiauthenticated";

   ...
}

Then explicitly state that we are interested in(register for) the UI_AUTHENTICATED broadcast message in LoginActivity.We register in the onResume activity lifecycle method and unregister in the onPause life cycle method.First we define the broadcast receiver.

...
private View mLoginFormView;
private BroadcastReceiver mBroadcastReceiver;
private Context mContext;
....

and put in the onResume and onPause methods as shown below.

public class LoginActivity extends AppCompatActivity
{

    ...
    private BroadcastReceiver mBroadcastReceiver;
    private Context mContext;
   ...

   

    @Override
    protected void onPause() {
        super.onPause();
        this.unregisterReceiver(mBroadcastReceiver);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {

                String action = intent.getAction();
                switch (action)
                {
                    case RoosterConnectionService.UI_AUTHENTICATED:
                        Log.d(TAG,"Got a broadcast to show the main app window");
                        //Show the main app window
                        showProgress(false);
                        Intent i2 = new Intent(mContext,ContactListActivity.class);
                        startActivity(i2);
                        finish();
                        break;
                }

            }
        };
        IntentFilter filter = new IntentFilter(RoosterConnectionService.UI_AUTHENTICATED);
        this.registerReceiver(mBroadcastReceiver, filter);
    }

      ...
}

With this in place ,we can add a method to RoosterConnection that sends the broadcast

private void showContactListActivityWhenAuthenticated()
{
    Intent i = new Intent(RoosterConnectionService.UI_AUTHENTICATED);
    i.setPackage(mApplicationContext.getPackageName());
    mApplicationContext.sendBroadcast(i);
    Log.d(TAG,"Sent the broadcast that we are authenticated");
}

and call it when the user is authenticated

@Override
public void authenticated(XMPPConnection connection) {
    RoosterConnectionService.sConnectionState=ConnectionState.CONNECTED;
    Log.d(TAG,"Authenticated Successfully");
    showContactListActivityWhenAuthenticated();

}

Run the app ,and type in your jid and password as usual.The ContactListActivity should show up at successful authentication.

Sending and Receiving Messages

To be able to send messages ,we need to carry out the following changes in ChatActivity

public class ChatActivity extends AppCompatActivity {
    private static final String TAG ="ChatActivity";

    private String contactJid;
    private ChatView mChatView;
    private SendButton mSendButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_chat);
        mChatView =(ChatView) findViewById(R.id.rooster_chat_view);
        mChatView.setEventListener(new ChatViewEventListener() {
            @Override
            public void userIsTyping() {
                //Here you know that the user is typing
            }

            @Override
            public void userHasStoppedTyping() {
                //Here you know that the user has stopped typing.
            }
        });

        mSendButton = mChatView.getSendButton();
        mSendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                //Only send the message if the client is connected
                //to the server.

                if (RoosterConnectionService.getState().equals(RoosterConnection.ConnectionState.CONNECTED)) {
                    Log.d(TAG, "The client is connected to the server,Sendint Message");
                    //Send the message to the server

                    Intent intent = new Intent(RoosterConnectionService.SEND_MESSAGE);
                    intent.putExtra(RoosterConnectionService.BUNDLE_MESSAGE_BODY,
                            mChatView.getTypedString());
                    intent.putExtra(RoosterConnectionService.BUNDLE_TO, contactJid);

                    sendBroadcast(intent);

                    //Update the chat view.
                    mChatView.sendMessage();
                } else {
                    Toast.makeText(getApplicationContext(),
                            "Client not connected to server ,Message not sent!",
                            Toast.LENGTH_LONG).show();
                }
            }
        });

        Intent intent = getIntent();
        contactJid = intent.getStringExtra("EXTRA_CONTACT_JID");
        setTitle(contactJid);
    }
}

Again we have a situation of passing a message from the UI thread to the background thread ,using RoosterConnection to send the message.We use the same mechanism of broadcasts ,only now ChatActivity is sending the broadcast and RoosterConnection is receiving it.The message types you see in the clickListener of mSendButton are defined in RoosterConnectionService as shown below.

private static final String TAG ="RoosterService";

public static final String UI_AUTHENTICATED = "com.blikoon.rooster.uiauthenticated";
public static final String SEND_MESSAGE = "com.blikoon.rooster.sendmessage";
public static final String BUNDLE_MESSAGE_BODY = "b_body";
public static final String BUNDLE_TO = "b_to";

public static RoosterConnection.ConnectionState sConnectionState;

RoosterConnection needs to register to receive these messages.We define the BroadCastReceiver

private XMPPTCPConnection mConnection;
private BroadcastReceiver uiThreadMessageReceiver;//Receives messages from the ui thread.
...

add a method the does the actual registering and sends the message to the server when the UI thread passes the message

private void setupUiThreadBroadCastMessageReceiver()
{
    uiThreadMessageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            //Check if the Intents purpose is to send the message.
            String action = intent.getAction();
            if( action.equals(RoosterConnectionService.SEND_MESSAGE))
            {
                //SENDS THE ACTUAL MESSAGE TO THE SERVER
                sendMessage(intent.getStringExtra(RoosterConnectionService.BUNDLE_MESSAGE_BODY),
                        intent.getStringExtra(RoosterConnectionService.BUNDLE_TO));
            }
        }
    };

    IntentFilter filter = new IntentFilter();
    filter.addAction(RoosterConnectionService.SEND_MESSAGE);
    mApplicationContext.registerReceiver(uiThreadMessageReceiver,filter);

}

and add the actual sendMessage() method as shown below

private void sendMessage ( String body ,String toJid)
{
    Log.d(TAG,"Sending message to :"+ toJid);

    EntityBareJid jid = null;


    ChatManager chatManager = ChatManager.getInstanceFor(mConnection);

    try {
        jid = JidCreate.entityBareFrom(toJid);
    } catch (XmppStringprepException e) {
        e.printStackTrace();
    }
    Chat chat = chatManager.chatWith(jid);
    try {
        Message message = new Message(jid, Message.Type.chat);
        message.setBody(body);
        chat.send(message);

    } catch (SmackException.NotConnectedException e) {
        e.printStackTrace();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

Of all these ChatManager can be found in the Smack documentation .The line

 ChatManager chatManager = ChatManager.getInstanceFor(mConnection);

Gives us a ChatManager that we are going to use to get a Chat object that is in turn going to send the message.The line

Chat chat = chatManager.chatWith(jid);

creates our Chat object. The chatWith() method of the ChatManager takes a Jid we create with the line below

jid = JidCreate.entityBareFrom(toJid);

If any method doesn’t make sense , you can select it and hit “Ctrl+B”, Android Studio will take you straight to the documentation where you can read about it. We send the message down the pipe with the code block below

Message message = new Message(jid, Message.Type.chat);
message.setBody(body);
chat.send(message);

We simply package the Jid and the body into a Message object that we send down the netowork pipe with the send() method of the our Chat object.By now ,Rooster is fully capable of sending messages to any xmpp client in the world.Go back to ContactModel class and modify the populateWithInitialContacts() method to include at least one XMPP contact that you know is connected and able to receive messages.Mine is highlighted in the code snippet below.

private void populateWithInitialContacts(Context context)
{
    //Create the Foods and add them to the list;


    Contact contact1 = new Contact("usr10@someXmppServer.com");
    mContacts.add(contact1);
    Contact contact2 = new Contact("User2@server.com");
   ...
}

Run the app ,click on that contact to open his chatActivity ,type in some message and hit send.You can see below that my messages are getting across.

rooster_sending_message_processed

To really live up to the promises of this tutorial ,we need to be able to receive messages sent to us by other people.Remember the processMessage() override method we just created above?Messages land in there when our friends respond back to us.We modify the method as shown below.

public void connect() throws IOException,XMPPException,SmackException
{
    Log.d(TAG, "Connecting to server " + mServiceName);

    XMPPTCPConnectionConfiguration conf = XMPPTCPConnectionConfiguration.builder()
            .setXmppDomain(mServiceName)
            ....


    //Set up the ui thread broadcast message receiver.
    setupUiThreadBroadCastMessageReceiver();

    mConnection = new XMPPTCPConnection(conf);
    mConnection.addConnectionListener(this);
    try {
        Log.d(TAG, "Calling connect() ");
        mConnection.connect();
        mConnection.login(mUsername,mPassword);
        Log.d(TAG, " login() Called ");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    ChatManager.getInstanceFor(mConnection).addIncomingListener(new IncomingChatMessageListener() {
        @Override
        public void newIncomingMessage(EntityBareJid messageFrom, Message message, Chat chat) {
            ///ADDED
            Log.d(TAG,"message.getBody() :"+message.getBody());
            Log.d(TAG,"message.getFrom() :"+message.getFrom());

            String from = message.getFrom().toString();

            String contactJid="";
            if ( from.contains("/"))
            {
                contactJid = from.split("/")[0];
                Log.d(TAG,"The real jid is :" +contactJid);
                Log.d(TAG,"The message is from :" +from);
            }else
            {
                contactJid=from;
            }

            //Bundle up the intent and send the broadcast.
            Intent intent = new Intent(RoosterConnectionService.NEW_MESSAGE);
            intent.setPackage(mApplicationContext.getPackageName());
            intent.putExtra(RoosterConnectionService.BUNDLE_FROM_JID,contactJid);
            intent.putExtra(RoosterConnectionService.BUNDLE_MESSAGE_BODY,message.getBody());
            mApplicationContext.sendBroadcast(intent);
            Log.d(TAG,"Received message from :"+contactJid+" broadcast sent.");
            ///ADDED

        }
    });
...
}

We add a listener to listen on incoming messages with the line

ChatManager.getInstanceFor(mConnection).addIncomingListener(new IncomingChatMessageListener() {

IncomingChatMessageListener as an override called  newIncomingMessage. It is inside this override that we capture the received message.

@Override
public void newIncomingMessage(EntityBareJid messageFrom, Message message, Chat chat) {
    ///ADDED
    Log.d(TAG,"message.getBody() :"+message.getBody());
    Log.d(TAG,"message.getFrom() :"+message.getFrom());

    String from = message.getFrom().toString();

    String contactJid="";
    if ( from.contains("/"))
    {
        contactJid = from.split("/")[0];
        Log.d(TAG,"The real jid is :" +contactJid);
        Log.d(TAG,"The message is from :" +from);
    }else
    {
        contactJid=from;
    }

    //Bundle up the intent and send the broadcast.
    Intent intent = new Intent(RoosterConnectionService.NEW_MESSAGE);
    intent.setPackage(mApplicationContext.getPackageName());
    intent.putExtra(RoosterConnectionService.BUNDLE_FROM_JID,contactJid);
    intent.putExtra(RoosterConnectionService.BUNDLE_MESSAGE_BODY,message.getBody());
    mApplicationContext.sendBroadcast(intent);
    Log.d(TAG,"Received message from :"+contactJid+" broadcast sent.");
    ///ADDED

}

Basically the function extracts the jid of the sender and the actual message from the parameters of the function and wraps all that info into an intent that it uses to send the broadcast message.For this to work we added two message types in RoosterConnectionService

public static final String BUNDLE_TO = "b_to";

public static final String NEW_MESSAGE = "com.blikoon.rooster.newmessage";
public static final String BUNDLE_FROM_JID = "b_from";

public static RoosterConnection.ConnectionState sConnectionState;

The last thing we need to do is setup ChatActivity to receive those broadcast messages ,we already know how to do that.

public class ChatActivity extends AppCompatActivity {
   ...
    private SendButton mSendButton;
    private BroadcastReceiver mBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ........
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(mBroadcastReceiver);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                switch (action)
                {
                    case RoosterConnectionService.NEW_MESSAGE:
                        String from = intent.getStringExtra(RoosterConnectionService.BUNDLE_FROM_JID);
                        String body = intent.getStringExtra(RoosterConnectionService.BUNDLE_MESSAGE_BODY);

                        if ( from.equals(contactJid))
                        {
                            mChatView.receiveMessage(body);

                        }else
                        {
                            Log.d(TAG,"Got a message from jid :"+from);
                        }

                        return;
                }

            }
        };

        IntentFilter filter = new IntentFilter(RoosterConnectionService.NEW_MESSAGE);
        registerReceiver(mBroadcastReceiver,filter);


    }
}

When the broadcast receiver gets the message it tests to see if the message is of type NEW_MESSAGE.If the sender’s Jid is the same as the current chatActivitie’s contactJid ,we show the message in chatActivity ,otherwise we simply print a debug statement saying that we got some message.My shinny Rooster ChatActivity is shown below in action.

rooster_full_chat_processed

Like any xmpp client that respects itself ,Rooster can now connect to a server ,send and receive messages.Feels great to make it doesn’t it.It has a lot of serious problems as of now though ,for example if you hit the back button ,all your messages are lost and you need to do more work in managing your connections.But the purpose of this tutorial was getting new people up to the point of using smack in their own projects.If you hit any bumpy roads in this tutorial don’t hesitate to ping me in the comments below.The complete source code for this tutorial can be found at my git repository.I hope this has been informative to you and I would like to thank you for reading.


Complete step by step video Course on XMPP and Smack on Android now available. By the Same Author of this Tute.Help spread the news.

We publish both written&video tutorials on XMPP and it’s application on different platforms. Subscribe below to be among the first to be notified.


Liked this tutorial ? Would be great if you helped us back, here is how :

You can also join our XMPP Learner Square Group on Facebook to find like minded people!


Posted in android, Tutorials, xmpp and tagged , , , .

Daniel Gakwaya loves computer Hardware/Software.He is a Software Engineer at BLIKOON and lead developer of bliboard-The whiteboard system currently marketed by the company.He is known to hack around on any piece of tech that happens to pick his interest. More on his tech endeavors here
Follow him on Twitter

159 Comments

  1. Hi man!
    Thanks very much.
    I’m just getting this error: “java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.”
    Smack version 4.1.7

    Do i need some kind of ssl library?

    Greetings.

  2. thanks
    its nice working when i login it displays online user on spark client but when i send message, no process is done. How can i check receiver side message? Give me a solution

  3. hi, can you please guide me on how to reconnect to xmpp server? the case is when i try login and connects its working fine, and then when all of a sudden internet is not there it closes the connection. when internet comes back i have added to reconnect. the reconnection connects to xmpp and then shows stream conflict saying that Client is already logged in. can you help me with this? what is the proper reconnection process?

    thanks.

    • The issue you are facing is because Rooster does not handle stream / connection management.Rooster is kind of a getting started guide on smack .If you want a proper client that takes care of all those details (that uses smack) please have a look at xaber . Conversations is another client worth a look at that takes care of these issues,(it doesn’t use smack but the underlying concepts are the same.)

  4. Thanx for this nice tutorial!
    I can send Messages, but I can´t receive them :/
    I have implemented the ChatMessageListener but it seems that the
    @Override
    public void processMessage(Chat chat, Message message) {
    Methode is never called.
    Can u tell me what I can do?

    Thank u very much!

      • First of all, thanks for this great tuto and nore generally for sharing your knowledge with others.
        ! i experience exactly the same… send yes but receive no 🙁
        and i also noticed processMessage is not called (from mobile to mobile) however it’s surprisingly working with Pidgin (processMessage is called) !!!
        how is that possible with exactly the same code ??
        thanks for your answer

    • please do like this

      @Override
      public void authenticated(XMPPConnection connection, boolean resumed) {
      RoosterConnectionService.sConnectionState = ConnectionState.CONNECTED;
      Log.d(TAG, “Authenticated Successfully”);
      showContactListActivityWhenAuthenticated();
      chatManager = ChatManager.getInstanceFor(mConnection);
      chatManager.addChatListener(this);
      MultiUserChatManager.getInstanceFor(mConnection).addInvitationListener(this);

      }
      its working from my side

  5. hi .
    thanks alot
    when i run the apk in device and want login when in click sigin in button the app React no action and nothig change . and stay in first activity .
    please help me

  6. Hello.
    I use jappix.com (server)
    When i run the apk in device and send message to some user (user@jappix.com) in another device not shoving my message, but when i use web wersion jappix.com work fine. Why ?

    • Hi!
      I don’t know about jappix web version so I can’t be of help here.(May be it is filtering messages from unkown resources?). But any standard xmpp client should be able to receive messages sent by Rooster.

  7. Hello,

    Thank you very much for your Tuto.

    I have a noob question, i have an OpenFire server and i would like to use it with your app, where to declare it and how ?

    Thank you

  8. First of all, thanks for your generous work, your two recent tutorials (this one and about ReceiverView with MVC concept) are very detailed and well-written.

    During the execution of this exercise I’ve found an minor bug in your instructions.
    LoginActivity misses mContext variable assignment, this results in the error shown below:
    java.lang.RuntimeException: Error receiving broadcast Intent { act=rooster.uiauthenticated flg=0x10 pkg=rooster } in rooster.LoginActivity$3@c09717e
    Caused by: java.lang.NullPointerException: Attempt to invoke virtual method ‘java.lang.String android.content.Context.getPackageName()’ on a null object reference

    To fix the issue, replace it reference in onResume method of LoginActivity with context variable already passes as a parameter, like this:
    Intent i2 = new Intent(context,ContactListActivity.class);

  9. Hey!
    Thanks very much for the tutorial. I have downloaded the source from github. I am using an open fire xmpp server. I have two test users created.

    I am able to login using the users from two separate devices. And I have changed a row in the contact model to the corresponding username. Eg: “username”@ipaddress. But when I send messages, the other device doesn’t receive any.

    Any help is appreciated.

    Thanks

    • Hello Rao,
      May be a problem with the server(Openfire) filtering out messages?I have tested this only with an ejabberd server and it worked.If possible please test with other publicly known servers like “xmpp.jp”.I wish I had time to investigate more on this and help but I don’t right now.

      • Dear Daniel ! problem still persists, I have tested this on xmpp.jp. Its not working unfortunately. Kindly help us out, it will be much appreciated. Thanks.

      • hi daniel !! tested with xmpp.jp too !! problem still persists, please try to help us out !! much appreciated if you can please take out some time and help us out. This issue is being asked many times in the comments.

      • problem still persists even with xmpp.jp !!! please i request to take some time and look into this issue.. its serious and will solve your purpose of this tutorial !! Please help !!!

    • Dear Daniel !! Very nice of you for such a detailed tutorial and keep up the work !!
      This tutorial really serves good knowledge for understanding XMPP chat.

      But I am stuck on a issue and it is also reported by other as I can see in the comments too, I think you are not able to reproduce it, please help us out. I followed the following steps:

      1. After downloading and successfully building your project from Github,

      2. Created two test users abc@xmpp.jp and xyz@xmpp.jp.

      3. Now in order to make them communicate with each other, I have to create two different logins i.e. one from abc@xmpp.jp and other from xyz@xmpp.jp and add vice versa to contact list of each other.

      4. So, to do this I modified the contactModel class and added contact abc@xmpp.jp and logged in from credentials of xyz@xmpp.jp.

      private void populateWithInitialContacts(Context context)
      {
      //Create the Foods and add them to the list;

      Contact contact1 = new Contact(“abc@xmpp.jp”);
      mContacts.add(contact1);
      }

      5. And to prepare other client I added contact xyz@xmpp.jp and logged in from credentials of abc@xmpp.jp.

      private void populateWithInitialContacts(Context context)
      {
      //Create the Foods and add them to the list;

      Contact contact1 = new Contact(“xyz@xmpp.jp”);
      mContacts.add(contact1);
      }

      6. Now,I have two different devices ready to communicate with each other such that I have abc@xmpp.jp in contact list of xyz@xmpp.jp and vice versa.

      7. But, when I select the contact to send the message there is no message received at the other end. However, In a case where sender and receiver is same message is received i.e. login from abc@xmpp.jp and adding abc@xmmpp.jp to contact list.

      I am helpless because I have invested much time in this tutorial and this tutorial is just what I need to start with. I would request some of your time to this issue, only then it will solve your purpose and benefit learners like us.

      Thanks in advance.

  10. please help me sir, I’m making a family chat application(android) to keep us
    together, I’m good at java and android java to some level, i want on the app
    first installation for it to request that my uncle or brother or aunt sign Up
    with only their contact and then a short int is sent to them for verification
    then they type it and register them selves on the openfire server. Pls help me
    i dnt know how to do this…..i need to do this so that they will appreciate my
    work and finally see that I’m trying. Pls help me sir!

  11. Nice Tutorial, so much love from me. I would like you to hint me on how to write plugin for openfire xmpp server.
    and i would like to ask if it’s possible to request an image from xmpp openfire server? I would so much appreciate any suggestion,

  12. First of all, thanks for this great tuto and nore generally for sharing your knowledge with others. Please forgive me for putting last message at a wrong place 🙁
    ! i experience exactly the same… send yes but receive no
    and i also noticed processMessage is not called (from mobile to mobile) however it’s surprisingly working with Pidgin (processMessage is called) !!!
    how is that possible with exactly the same code ??
    thanks for your answer

  13. Hi gakwaya,
    Thanks for sharing such a nice tutorials.I am creating this one,and i have also tried your github source code.It login properly from conversation.im and xmpp.jp.But when i try to comunicate between two users,then messages will not share.
    Can you please help me in this regard.
    I shall be very thankful to you.

  14. Nice tutorial

    I think you forgot to mention calling the setupUiThreadBroadCastMessageReceiver
    from within the connect method in RoosterConnection.java its remarked out in the example above but enabled in the GIT

    best regards

    • I had the same problem with receiving messages – process message never fires
      I tried adding this after mConnection.login and it fires OK. Im using Openfire and the windows client Spark for testing

      StanzaTypeFilter message_filter = new StanzaTypeFilter(Message.class);
      mConnection.addSyncStanzaListener(new StanzaListener() {
      @Override
      public void processPacket(Stanza packet) throws SmackException.NotConnectedException {

      Log.i(TAG, “Processing Packet”);
      Message message = (Message)packet;
      if(message.getType() == Message.Type.chat) {
      String msg_xml = packet.toString();
      Log.i(TAG, “Message “+ msg_xml);
      if (msg_xml.contains(ChatState.gone.toString())) {
      //handle has closed chat
      Log.i(TAG, “Gone”);
      } else if (msg_xml.contains(ChatState.paused.toString())) {
      // handle “stopped typing”
      Log.i(TAG, “Paused”);
      } else {
      //single chat message
      Log.i(TAG, “Chat “+ message.getBody());
      }
      } else if(message.getType() == Message.Type.groupchat) {
      //group chat message
      Log.i(TAG, “GroupChat – “+ message.getBody());
      } else if(message.getType() == Message.Type.error) {
      //error message
      Log.i(TAG, “Error – “+ message.toXML());
      }

      }
      }, message_filter);

  15. Hi man thanks for posting.
    But i am facing the following problems while adding the dependencies in build.gradle. (I have added the internet permission in manifest.xml file)

    F:\MyBook\Android_Workspace\MyApplication2\app\build.gradle
    Error:(27, 13) Failed to resolve: org.igniterealtime.smack:smack-tcp:4.1.0-alpha6
    disable.gradle.offline.mode” rel=”nofollow”Disable offline mode and Sync/MyBook/Android_Workspace/MyApplication2/app/build.gradle” rel=”nofollow”Show in Filehref=”open.dependency.in.project.structure” rel=”nofollow”Show in Project Structure dialog
    Error:(26, 13) Failed to resolve: org.igniterealtime.smack:smack-android-extensions:4.1.0-alpha6
    href=”disable.gradle.offline.mode” rel=”nofollow”>Disable offline mode and Sync”/MyBook/Android_Workspace/MyApplication2/app/build.gradle” rel=”nofollow”Show in Filehref=”open.dependency.in.project.structure” rel=”nofollow”Show in Project Structure dialog

  16. hello all i am work with multiuserchat but i am not able to send message on group please can any one describe briefly how to implement …

  17. hello thanks for this tutorial but i got this error
    i have downloaded openfire.
    12-05 21:43:22.980 2361-2361/com.blikoon.rooster D/RoosterService: Service Start() function called.
    12-05 21:43:24.810 2361-14139/com.blikoon.rooster I/System.out: Unparsed type SOA
    12-05 21:45:32.120 2361-14139/com.blikoon.rooster D/RoosterService: Something went wrong while connecting ,make sure the credentials are right and try again
    12-05 21:45:32.120 2361-14139/com.blikoon.rooster W/System.err: org.jivesoftware.smack.SmackException$ConnectionException: The following addresses failed: openfire.com:5222 Exception: failed to connect to openfire.com/209.15.13.134 (port 5222): connect failed: ETIMEDOUT (Connection timed out)
    12-05 21:45:32.120 2361-14139/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectUsingConfiguration(XMPPTCPConnection.java:564)
    12-05 21:45:32.120 2361-14139/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectInternal(XMPPTCPConnection.java:822)
    12-05 21:45:32.120 2361-14139/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.AbstractXMPPConnection.connect(AbstractXMPPConnection.java:326)
    12-05 21:45:32.120 2361-14139/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnection.connect(RoosterConnection.java:86)
    12-05 21:45:32.120 2361-14139/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnectionService.initConnection(RoosterConnectionService.java:80)
    12-05 21:45:32.120 2361-14139/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnectionService.access$100(RoosterConnectionService.java:19)
    12-05 21:45:32.120 2361-14139/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnectionService$1.run(RoosterConnectionService.java:107)
    12-05 21:45:32.120 2361-14139/com.blikoon.rooster W/System.err: at java.lang.Thread.run(Thread.java:818)
    12-05 21:45:32.150 2361-2361/com.blikoon.rooster D/RoosterService: onDestroy()
    12-05 21:45:32.150 2361-2361/com.blikoon.rooster D/RoosterService: stop()
    12-05 21:45:32.150 2361-14139/com.blikoon.rooster D/RoosterConnection: Disconnecting from serser openfire.com
    12-05 21:45:32.150 2361-14139/com.blikoon.rooster W/System.err: org.jivesoftware.smack.SmackException$NotConnectedException: Client is not, or no longer, connected
    12-05 21:45:32.150 2361-14139/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.AbstractXMPPConnection.disconnect(AbstractXMPPConnection.java:599)
    12-05 21:45:32.150 2361-14139/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.AbstractXMPPConnection.disconnect(AbstractXMPPConnection.java:583)
    12-05 21:45:32.150 2361-14139/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnection.disconnect(RoosterConnection.java:170)
    12-05 21:45:32.150 2361-14139/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnectionService$2.run(RoosterConnectionService.java:130)
    12-05 21:45:32.150 2361-14139/com.blikoon.rooster W/System.err: at android.os.Handler.handleCallback(Handler.java:739)
    12-05 21:45:32.150 2361-14139/com.blikoon.rooster W/System.err: at android.os.Handler.dispatchMessage(Handler.java:95)
    12-05 21:45:32.150 2361-14139/com.blikoon.rooster W/System.err: at android.os.Looper.loop(Looper.java:135)
    12-05 21:45:32.150 2361-14139/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnectionService$1.run(RoosterConnectionService.java:109)
    12-05 21:45:32.150 2361-14139/com.blikoon.rooster W/System.err: at java.lang.Thread.run(Thread.java:818)

    tell me whats wrong with this?

  18. sir i have an instant messaging app running on tigase perfectly but how can i make this server open to public i.e upload it online

  19. Hello Daniel,

    Thanks for such an awesome Article…!
    I followed it and implemented small chatting module using Openfire.

    I need your help, on one more functionality, how to get one to one chat history on mobile from server to device?

    Currently I am using MamManager from Smack. But MamManager.isSupportedByServer() is returning false.
    I referred some links which tells that have to add Monitoring service on Openfire but still returning same I am using Openfire 4.1.0 & Smack 4.2.0-beta2.

    Thanks

    • Hello David,Thanks for the kind comment.
      Unfortunately I don’t use Openfire and I have no idea as to why retrieving Mam history is not working for you.If you join this muc “open_chat@conference.igniterealtime.org” you may get in touch with people that can help.The developpers of both smack and Openfire are
      pretty active in there and you might get a better response.Cheers!

  20. Hi Daniel,

    I’ve setup my own XMPP server in Ubuntu using .deb installer file. Now when I’m trying to connect to the XMPP server from my Android client using XMPPTCPConnection it is failing with SSLHandshakeException “Connection closed with error javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found”.

    Could you throw some light on what’s going wrong here and how would I be able to fix the problem?

    Following is the error log,
    ****************************************
    02-01 15:55:22.626 32092-32177/com.aricent.chat.samplechatwithsmack D/SMACK: RECV (0):
    02-01 15:55:22.627 32092-32177/com.aricent.chat.samplechatwithsmack D/SMACK: RECV (0): PLAINDIGEST-MD5X-OAUTH2SCRAM-SHA-1
    02-01 15:55:22.628 32092-32176/com.aricent.chat.samplechatwithsmack D/SMACK: SENT (0):
    02-01 15:55:22.671 32092-32177/com.aricent.chat.samplechatwithsmack D/SMACK: RECV (0):
    02-01 15:55:22.762 32092-32177/com.aricent.chat.samplechatwithsmack W/AbstractXMPPConnection: Connection closed with error
    javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:322)
    at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:623)
    at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:585)
    at org.jivesoftware.smack.tcp.XMPPTCPConnection.initReaderAndWriter(XMPPTCPConnection.java:658)
    at org.jivesoftware.smack.tcp.XMPPTCPConnection.proceedTLSReceived(XMPPTCPConnection.java:765)
    at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$1000(XMPPTCPConnection.java:139)
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1022)
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:956)
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:971)
    at java.lang.Thread.run(Thread.java:818)
    Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
    at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:318)
    at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:219)
    at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:114)
    at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:550)
    at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:318)
    at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:623) 
    at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:585) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection.initReaderAndWriter(XMPPTCPConnection.java:658) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection.proceedTLSReceived(XMPPTCPConnection.java:765) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$1000(XMPPTCPConnection.java:139) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1022) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:956) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:971) 
    at java.lang.Thread.run(Thread.java:818) 
    Caused by: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
    at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:318) 
    at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:219) 
    at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:114) 
    at com.android.org.conscrypt.OpenSSLSocketImpl.verifyCertificateChain(OpenSSLSocketImpl.java:550) 
    at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method) 
    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:318) 
    at com.android.org.conscrypt.OpenSSLSocketImpl.waitForHandshake(OpenSSLSocketImpl.java:623) 
    at com.android.org.conscrypt.OpenSSLSocketImpl.getInputStream(OpenSSLSocketImpl.java:585) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection.initReaderAndWriter(XMPPTCPConnection.java:658) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection.proceedTLSReceived(XMPPTCPConnection.java:765) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection.access$1000(XMPPTCPConnection.java:139) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1022) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:956) 
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:971) 
    at java.lang.Thread.run(Thread.java:818) 
    02-01 15:55:22.763 32092-32177/com.aricent.chat.samplechatwithsmack D/xmpp: ConnectionClosedOn Error!
    02-01 15:55:22.764 32092-32166/com.aricent.chat.samplechatwithsmack E/(Service): SMACKException: javax.net.ssl.SSLHandshakeException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
    ****************************************

    Thanks,
    Prem

    • Hi,
      You probably need to configure ssl certificates for your server to be able to connect with tls.Or you can disable encrypted connections in your client.But disabling encrypted connections is very dangerous you should do this ONLY in test environements.
      Good luck.

        • Something like this:
          xmppConfig.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
          in your connection routine.This is off the top my head and I haven’t used smack for a while.You should check the official API just to play it safe.
          Good luck.

  21. Dear Daniel !! Very nice of you for such a detailed tutorial and keep up the work !!
    This tutorial really serves good knowledge for understanding XMPP chat.

    But I am stuck on a issue and it is also reported by other as I can see in the comments too, I think you are not able to reproduce it, please help us out. I followed the following steps:

    1. After downloading and successfully building your project from Github,

    2. Created two test users abc@xmpp.jp and xyz@xmpp.jp.

    3. Now in order to make them communicate with each other, I have to create two different logins i.e. one from abc@xmpp.jp and other from xyz@xmpp.jp and add vice versa to contact list of each other.

    4. So, to do this I modified the contactModel class and added contact abc@xmpp.jp and logged in from credentials of xyz@xmpp.jp.

    private void populateWithInitialContacts(Context context)
    {
    //Create the Foods and add them to the list;

    Contact contact1 = new Contact(“abc@xmpp.jp”);
    mContacts.add(contact1);
    }

    5. And to prepare other client I added contact xyz@xmpp.jp and logged in from credentials of abc@xmpp.jp.

    private void populateWithInitialContacts(Context context)
    {
    //Create the Foods and add them to the list;

    Contact contact1 = new Contact(“xyz@xmpp.jp”);
    mContacts.add(contact1);
    }

    6. Now,I have two different devices ready to communicate with each other such that I have abc@xmpp.jp in contact list of xyz@xmpp.jp and vice versa.

    7. But, when I select the contact to send the message there is no message received at the other end. However, In a case where sender and receiver is same message is received i.e. login from abc@xmpp.jp and adding abc@xmmpp.jp to contact list.

    I am helpless because I have invested much time in this tutorial and this tutorial is just what I need to start with. I would request some of your time to this issue, only then it will solve your purpose and benefit learners like us.

    Thanks in advance.

  22. Dear Daniel !! Very nice of you for such a detailed tutorial and keep up the work !!
    This tutorial really serves good knowledge for understanding XMPP chat.

    But I am stuck on a issue and it is also reported by other as I can see in the comments too, I think you are not able to reproduce it, please help us out. I followed the following steps:

    1. After downloading and successfully building your project from Github,

    2. Created two test users abc@xmpp.jp and xyz@xmpp.jp.

    3. Now in order to make them communicate with each other, I have to create two different logins i.e. one from abc@xmpp.jp and other from xyz@xmpp.jp and add vice versa to contact list of each other.

    • When post a message it has to be approved by the moderator to bee seen here.Otherwise we get many garbage spamy messages.I do my best to check as often as possible.

  23. I finally had some free time to look into the problem of messages not being received by Rooster and applied a fix.The tests I have conducted have shown that I can send and receive messages to/from Rooster and when Rooster is talking to another xmpp client.I used Conversations for this tests.The server I have used is Prosody 0.10.Hope this fixes the problem for you guys.
    The details of the fix can be found in this git commit :
    https://github.com/blikoon/Rooster/commit/cd00718b3c1abf38483bfe65f5ad1a378035ca45#diff-ec8e92025fb2cd50d04c2fc3f23f49f7

  24. It is not in this tuto; But I will ask you to help me; I would like that when sending a message while ChatActivity is not visible, it indicates a notification; Once you click on the notification it opens ChatActivity

    Please help me
    Thank you

  25. It is not in this tuto; But I will ask you to help me; I would like that when receive a message while ChatActivity is not visible, it indicates a notification; Once you click on the notification it opens ChatActivity

    Please help me
    Thank you

  26. One question Daniel !!

    I am working on a chat app, yes a multi user chat having features alike whatsapp such as message notifications while app in background, user typing…, message sent-uploaded-seen by user, and many more as u know.. sending a voice/video recorded message and file transfer in a later phase..!!

    This tutorial seems very nice start for me.. does this project can be applied with these features ? Or the requirements needs some other way of implementation ? I know Rooster is using activities rather a tabbed activity and fragments but thats UI and its not as much concern.

    Thanks.

    • Hi Jason,
      Yes Rooster can be a basis for your project but it really isn’t doing anything fancy.Smack is doing all the heavy lifting.If you want to extend it, you should read smack docs an you should be able to do most of what you want.

      However,there are many open source projects that have used smack to implement most if not all the cool features you want. Kontalk and Xabber come to mind. If you don’t mind basing your work on top of them ,they really are worth a shot.
      Good luck.

      • Yes, Thanks Daniel !! I am seeing Xabber and conversations for reference.. a lot of code there mostly complex and will definitely need certain a level of programming to understand it. Kontalk I will just check it out.

        Thanks again for your fixes, app works like a charm !!!

          • Hi again !! Daniel, can you suggest some open sources, something to take this a level up !! Open Projects like conversations and xabber, am facing a hard time with them..

            thanks,

          • Hey, most of these projects have years of development so they are understandably complex. I would suggest first laying down what you want to do in a list and take them down one by one. If you face any problem ask in the the smack/openfire MUC .If you are specific in what problem you are having ,somebody is usually happy to give you a helping hand.

  27. Hi dear,
    it is very helpful for me as i am fresher in chat apps . But it just showing the messages on one device(on same device) which are sent by us. it is not showing recieved message . plz discuss how we can send and receive message on each other device. Even i tried with two devices with different different user with same contact as ‘user@testServer.com’
    pls help me and also provide your gmail id also for future help.

    • Hi,
      I am not sure I am getting your problem right, Rooster is installed on device A and B ,A can send to B and B can receive but B can send to A and A is not receiving?Also please post relevant debug output here so we stand a chance at seeing what is going wrong.Also the android versions your devices are running.

      • I have installed the Rooster application on two devices (device A and device B). On both devices i have tried with same email password as well as different email password also. On both devices, I have tried with same contact as ‘user@testServer.com’ as well as different contact also. But A just showing sent message but that message is not received by any device (not also device B). As it B just showing sent message but that message is not received by anyone. Means both devices just sending the message but not receiving the message. I trying with device A (Model :- M! 4W and version:- 6.0.1 MMB29M) and device B (Model :- vivo Y51L and version:- 5.0.2)
        Please suggest to me about this that how i can communicate with each other.

        • Dont use vivo for testing !!! I had a bad time with it..!! vivo sucks with broadcast receivers, and also kills you app(main process and its service) as soon as you move out app from the recent app tray.

          Wasted my time and money on vivo.

  28. Hi
    I am trying this demo with two different-different device with different-different user ids.
    I am logging successfully but i can only send the message on both side ,not recieving the message or each other.
    Plz suggest me about it.

  29. Guys..!! Message not received on other device issue is -SOLVED.

    Regarding the issue about receiving the messages on other device..

    First read the code.. let yourself know the process.

    inside chatActivity

    @override
    onResume()
    onBroadcastRecieve

    1 if ( from.equals(contactJid))
    2 {
    3 mChatView.receiveMessage(body);
    4
    5 }else
    6 {
    7 Log.d(TAG,”Got a message from jid :”+from+”msg is: “+body);

    1. Line 1 : The code says it will only display a message in chatActivity if user and sender are same.

    2. Line 7: It does nothing just displays the message in log and You have to implement that part.

    Just try to send a message with sender and receiver as same.. check the debug logs !! U will see the message in chatActivity and in logs too.

  30. Hello I installed the app but can’t sign in what do I do or what exactly am I suppose to input as the username and password. Help please

  31. Hello @gakwaya …
    Thank you for the great tutorial for the xmpp beginners..i followed your tutorial and everything running smooth and now am trying to fetch the typing or composing status using your tutorial code…can you please share some knowledge about how to fetch typing or composing status using this tutorial…

    Thank You in Advance….

  32. hi .
    this is an awesome tutorial.
    I m using Android Studio 2.3 and installed latest ejabberd. refactored the code to match to latest dependencies.

    dependencies {
    compile fileTree(include: [‘*.jar’], dir: ‘libs’)
    compile ‘com.android.support:appcompat-v7:25.3.0’
    compile ‘com.android.support:design:25.3.0’
    compile ‘co.devcenter.square:android-ui-library:0.1’
    compile ‘org.igniterealtime.smack:smack-android-extensions:4.1.0-alpha6’
    compile ‘org.igniterealtime.smack:smack-tcp:4.1.0-alpha6’
    testCompile ‘junit:junit:4.12’
    }

    When the android emulator loads with login UI, I am unable to login.
    Log message:
    Connected to the target VM, address: ‘localhost:8630’, transport: ‘socket’, there is no exception

    • after some time I got the error org.jivesoftware.smack.SmackException$ConnectionException: The following addresses failed: localhost:5222 Exception: Connection refused

      I checked ejabberd, by executing following command

      sbin/ejabberdctl status
      The node ejabberd@localhost is started with status: started
      ejabberd 17.03.beta-63 is running in that node

      • I resolved this, by adding

        builder.setHost(“10.0.2.2”);
        builder.setPort(5222);
        builder.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);

  33. Hi daniel !! just to inform you..

    I am working on your project and has added some features..
    like autologin.. (was already there but a bit improved now)
    add and delete contact..
    receive and update contacts on contactsActivity.java..
    receive and update respective contact item on new message received..
    corresponding time the message received and number of messages received for a particular contact item view… !!
    Created a database for entering chat messages for current connection session..!

    In progress..
    display picture..
    message handling to be implemented in background..
    typing.. (state when other user is typing message)
    online/offline status..
    and further..!!!

    Still struggling with XMPPconnection stability and re-connection mechanism..!

    If any suggestion.. may kindly reply..!

    P.S: If you want we can update the current GitHub project and make rooster grow ! Thanks.

    • Hello Jason,
      Sounds interesting what you’re doing there. But I am more interested in explaining the process of building that so it is easy to understand for readers. Simply merging in new code would confuse people coming from this tutorial.
      If possible, would you like to document what you have done into a tutorial and post it somewhere? I would happily link to your work for people who want to take this further. That would actually have a huge audience as I get lots of emails requesting to take this to the next step but I currently I am short on time to do so.
      Let me know what you think.

      • That sounds great !! This is exactly what I want.

        That will a lot of learners as I am one and I remember when your tutorial gave me a good start for my project. I would definitely like take it further.

        The code is pretty simple as yours. Commented and Logged pretty well.

        Since then, I have implemented receiving messages in background and notifications for messages as well.

        I will get back to you soon when I am done with my basic IM chat application and will work as you desired.

      • Hello Jason ,

        I want to implement typing notification. can you plz help me how to implement this. there is no listener for this.

  34. Please tell me how can i customize chat view with images and custom backgrounds on chat view messages

    • The chatView is powered by a third party library in Rooster. May be they provide an interface to change backgrounds.You should check that. But if you do your own chatView, you can easily apply a background to the the root layout containing the RecyclerView. Of course that is if you use the RecyclerView. Hope this helps.

  35. Hii…. Its an awesome tuturial for xmpp android chat. I realy likes it.
    So i have few doubts, in my application am using smack as per the tutorial. It was fine for text messages. Bu now i need to transfer file through it but i cant customize the smack xml atributes. In my other end ios sending xml with a attach ment tag but my end smack skippes those tags.. So please suggest a solution for this.
    Thanks in adavance

  36. Hi Gakwaya,
    Thanks for the awesome tutorial!

    I am getting the following error when i send the message from chat activity.
    Please help!

    E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.networktasksdemo, PID: 6186
    java.lang.RuntimeException: Error receiving broadcast Intent { act=com.example.sendmessage flg=0x10 (has extras) } in com.example.networktasksdemo.MyXMPPConnection$4@584d035
    at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:893)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5441)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628)
    Caused by: java.lang.NullPointerException
    at java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:847)
    at java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:842)
    at org.jivesoftware.smack.chat.ChatManager.createChat(ChatManager.java:251)
    at org.jivesoftware.smack.chat.ChatManager.createChat(ChatManager.java:243)
    at org.jivesoftware.smack.chat.ChatManager.createChat(ChatManager.java:224)
    at com.example.networktasksdemo.MyXMPPConnection.sendMessage(MyXMPPConnection.java:221)
    at com.example.networktasksdemo.MyXMPPConnection.access$200(MyXMPPConnection.java:32)
    at com.example.networktasksdemo.MyXMPPConnection$4.onReceive(MyXMPPConnection.java:201)
    at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:883)
    at android.os.Handler.handleCallback(Handler.java:739) 
    at android.os.Handler.dispatchMessage(Handler.java:95) 
    at android.os.Looper.loop(Looper.java:148) 
    at android.app.ActivityThread.main(ActivityThread.java:5441) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:738) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:628) 
    I/Process: Sending signal. PID: 6186 SIG: 9
    Application terminated.

    • Hi,
      are you seeing the same error when compile the code from github as is? Can’t really know what is going wrong for you without some code context.

  37. Hi,
    This is Great tutorial. thank you.
    for developing it, i need your help.
    I want to receive pushnotification in device when the special jid send broadcast message .so i try it :

    in the RoosterConnection.java :

    messageListener = new ChatMessageListener() {
    @Override
    public void processMessage(Chat chat, Message message) {
    ///ADDED
    Log.d(TAG,”message.getBody() :”+message.getBody());
    Log.d(TAG,”message.getFrom() :”+message.getFrom());

    String from = message.getFrom();
    String contactJid=””;

    if ( from.contains(“/”))
    {
    contactJid = from.split(“/”)[0];
    Log.d(TAG,”The real jid is :” +contactJid);
    }else
    {
    contactJid=from;
    if ( contactJid.equals(“specialJid”)) // this is my code
    {
    Log.d(TAG,”deliver:”+contactJid);
    RecieveServerMsg(contactJid ,matn );

    } //ending
    }

    //Bundle up the intent and send the broadcast.
    Intent intent = new Intent(RoosterConnectionService.NEW_MESSAGE);
    intent.setPackage(mApplicationContext.getPackageName());
    intent.putExtra(RoosterConnectionService.BUNDLE_FROM_JID,contactJid);
    intent.putExtra(RoosterConnectionService.BUNDLE_MESSAGE_BODY,message.getBody());
    mApplicationContext.sendBroadcast(intent);
    Log.d(TAG,”Received message from :”+contactJid+” broadcast sent.”);
    ///ADDED

    }

    };

    —————
    and next add this function:
    public void RecieveServerMsg(String from , String msg) {
    Log.d(TAG,”roosterRecivam :1″);
    NotificationView inst = new NotificationView();
    inst.addNotification();
    }
    //
    ———–
    and next after create customnotif.xml , create NotificationView class:

    import android.app.Activity;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.os.Bundle;
    import android.support.v4.app.NotificationCompat;

    /**
    * Created by sabina on 6/5/2017.
    */
    public class NotificationView extends Activity {
    int id = 1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.custom_notif);
    }

    public void addNotification() {

    NotificationCompat.Builder builder =
    new NotificationCompat.Builder(this)
    .setSmallIcon(R.drawable.icon)
    .setContentTitle(“Notifications Example”)
    .setContentText(“This is a test notification”);

    Intent notificationIntent = new Intent(this, NotificationView.class);
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent,
    PendingIntent.FLAG_UPDATE_CURRENT);
    builder.setContentIntent(contentIntent);

    // Add as notification
    NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    manager.notify(id, builder.build());
    }
    }
    ————————————–
    and in manifestAndroid:

    ==========================================
    but after compile it , i get this error:
    06-06 13:28:03.204 2364-3752/com.blikoon.rooster E/AbstractXMPPConnection: Exception in packet listener
    java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
    at android.os.Handler.(Handler.java:200)
    at android.os.Handler.(Handler.java:114)
    at android.app.Activity.(Activity.java:754)
    at com.blikoon.rooster.NotificationView.(NotificationView.java:0)
    at com.blikoon.rooster.RoosterConnection.RecieveServerMsg(RoosterConnection.java:164)
    at com.blikoon.rooster.RoosterConnection$1.processMessage(RoosterConnection.java:122)
    at org.jivesoftware.smack.Chat.deliver(Chat.java:177)
    at org.jivesoftware.smack.ChatManager.deliverMessage(ChatManager.java:336)
    at org.jivesoftware.smack.ChatManager.access$300(ChatManager.java:48)
    at org.jivesoftware.smack.ChatManager$2.processPacket(ChatManager.java:157)
    at org.jivesoftware.smack.AbstractXMPPConnection.invokePacketCollectorsAndNotifyRecvListeners(AbstractXMPPConnection.java:880)
    at org.jivesoftware.smack.AbstractXMPPConnection$ListenerNotification.run(AbstractXMPPConnection.java:851)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:423)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
    at java.lang.Thread.run(Thread.java:818)

    ==============================

  38. I am getting below error…how can i resolve it ?

    07-03 11:07:39.942 31514-31514/com.blikoon.rooster D/RoosterService: onCreate()
    07-03 11:07:39.943 31514-31514/com.blikoon.rooster D/RoosterService: onStartCommand()
    07-03 11:07:39.943 31514-31514/com.blikoon.rooster D/RoosterService: Service Start() function called.
    07-03 11:07:39.945 31514-31830/com.blikoon.rooster D/RoosterService: initConnection()
    07-03 11:07:39.951 31514-31830/com.blikoon.rooster D/RoosterConnection: RoosterConnection Constructor called.
    07-03 11:07:39.951 31514-31830/com.blikoon.rooster D/RoosterConnection: Connecting to server xmpp.jp
    07-03 11:07:40.467 31514-31840/com.blikoon.rooster W/AbstractXMPPConnection: Connection closed with error
    java.net.SocketException: Connection reset
    at java.net.SocketInputStream.read(SocketInputStream.java:192)
    at java.net.SocketInputStream.read(SocketInputStream.java:120)
    at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:287)
    at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:350)
    at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:179)
    at java.io.InputStreamReader.read(InputStreamReader.java:184)
    at java.io.BufferedReader.read1(BufferedReader.java:221)
    at java.io.BufferedReader.read(BufferedReader.java:297)
    at org.kxml2.io.KXmlParser.fillBuffer(KXmlParser.java:1535)
    at org.kxml2.io.KXmlParser.peekType(KXmlParser.java:1007)
    at org.kxml2.io.KXmlParser.next(KXmlParser.java:357)
    at org.kxml2.io.KXmlParser.next(KXmlParser.java:321)
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1170)
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$200(XMPPTCPConnection.java:931)
    at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:950)
    07-03 11:07:40.468 31514-31840/com.blikoon.rooster D/RoosterConnection: ConnectionClosedOnError, error java.net.SocketException: Connection reset
    07-03 11:07:45.450 31514-31830/com.blikoon.rooster D/RoosterService: Something went wrong while connecting ,make sure the credentials are right and try again
    07-03 11:07:45.450 31514-31830/com.blikoon.rooster W/System.err: org.jivesoftware.smack.SmackException$NoResponseException: No response received within packet reply timeout. Timeout was 5000ms (~5s)
    07-03 11:07:45.450 31514-31830/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.SynchronizationPoint.checkForResponse(SynchronizationPoint.java:176)
    07-03 11:07:45.450 31514-31830/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.SynchronizationPoint.checkIfSuccessOrWait(SynchronizationPoint.java:110)
    07-03 11:07:45.450 31514-31830/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.SynchronizationPoint.checkIfSuccessOrWaitOrThrow(SynchronizationPoint.java:93)
    07-03 11:07:45.450 31514-31830/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection.connectInternal(XMPPTCPConnection.java:825)
    07-03 11:07:45.450 31514-31830/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.AbstractXMPPConnection.connect(AbstractXMPPConnection.java:326)
    07-03 11:07:45.451 31514-31830/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnection.connect(RoosterConnection.java:88)
    07-03 11:07:45.451 31514-31830/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnectionService.initConnection(RoosterConnectionService.java:80)
    07-03 11:07:45.451 31514-31830/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnectionService.access$100(RoosterConnectionService.java:19)
    07-03 11:07:45.451 31514-31830/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnectionService$1.run(RoosterConnectionService.java:107)
    07-03 11:07:45.451 31514-31830/com.blikoon.rooster W/System.err: at java.lang.Thread.run(Thread.java:762)
    07-03 11:07:45.452 31514-31514/com.blikoon.rooster D/RoosterService: onDestroy()
    07-03 11:07:45.452 31514-31514/com.blikoon.rooster D/RoosterService: stop()
    07-03 11:07:45.453 31514-31830/com.blikoon.rooster D/RoosterConnection: Disconnecting from serser xmpp.jp
    07-03 11:07:45.455 31514-31830/com.blikoon.rooster W/System.err: org.jivesoftware.smack.SmackException$NotConnectedException: Client is not, or no longer, connected
    07-03 11:07:45.456 31514-31830/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.AbstractXMPPConnection.disconnect(AbstractXMPPConnection.java:599)
    07-03 11:07:45.456 31514-31830/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.AbstractXMPPConnection.disconnect(AbstractXMPPConnection.java:583)
    07-03 11:07:45.456 31514-31830/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnection.disconnect(RoosterConnection.java:184)
    07-03 11:07:45.456 31514-31830/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnectionService$2.run(RoosterConnectionService.java:130)
    07-03 11:07:45.456 31514-31830/com.blikoon.rooster W/System.err: at android.os.Handler.handleCallback(Handler.java:751)
    07-03 11:07:45.456 31514-31830/com.blikoon.rooster W/System.err: at android.os.Handler.dispatchMessage(Handler.java:95)
    07-03 11:07:45.456 31514-31830/com.blikoon.rooster W/System.err: at android.os.Looper.loop(Looper.java:154)
    07-03 11:07:45.456 31514-31830/com.blikoon.rooster W/System.err: at com.blikoon.rooster.RoosterConnectionService$1.run(RoosterConnectionService.java:109)
    07-03 11:07:45.456 31514-31830/com.blikoon.rooster W/System.err: at java.lang.Thread.run(Thread.java:762)
    07-03 11:09:39.842 31514-31514/com.blikoon.rooster V/InputMethodManager: Starting input: tba=android.view.inputmethod.EditorInfo@f2f0bcd nm : com.blikoon.rooster ic=com.android.internal.widget.EditableInputConnection@a2eac82
    07-03 11:09:39.843 31514-31514/com.blikoon.rooster I/InputMethodManager: [IMM] startInputInner – mService.startInputOrWindowGainedFocus
    07-03 11:09:39.848 31514-31514/com.blikoon.rooster D/InputTransport: Input channel constructed: fd=102
    07-03 11:09:39.848 31514-31514/com.blikoon.rooster D/InputTransport: Input channel destroyed: fd=84
    07-03 11:09:39.852 31514-31514/com.blikoon.rooster W/IInputConnectionWrapper: finishComposingText on inactive InputConnection
    07-03 11:09:39.959 31514-31514/com.blikoon.rooster W/IInputConnectionWrapper: getCursorCapsMode on inactive InputConnection
    07-03 11:09:39.997 31514-31514/com.blikoon.rooster W/IInputConnectionWrapper: getCursorCapsMode on inactive InputConnection
    07-03 11:09:40.071 31514-31514/com.blikoon.rooster W/IInputConnectionWrapper: getSelectedText on inactive InputConnection
    07-03 11:09:40.073 31514-31514/com.blikoon.rooster W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection
    07-03 11:09:40.075 31514-31514/com.blikoon.rooster W/IInputConnectionWrapper: getTextAfterCursor on inactive InputConnection
    07-03 11:09:40.100 31514-31514/com.blikoon.rooster W/IInputConnectionWrapper: getSelectedText on inactive InputConnection
    07-03 11:09:40.102 31514-31514/com.blikoon.rooster W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection
    07-03 11:09:40.104 31514-31514/com.blikoon.rooster W/IInputConnectionWrapper: getTextAfterCursor on inactive InputConnection
    07-03 11:09:45.292 31514-31514/com.blikoon.rooster D/ViewRootImpl@66c51fe[LoginActivity]: MSG_RESIZED_REPORT: frame=Rect(0, 0 – 1536, 2048) ci=Rect(0, 48 – 0, 0) vi=Rect(0, 48 – 0, 0) or=1
    07-03 11:09:45.322 31514-31514/com.blikoon.rooster D/ViewRootImpl@66c51fe[LoginActivity]: Relayout returned: oldFrame=[0,0][1536,2048] newFrame=[0,0][1536,2048] result=0x3 surface={isValid=true 547675805696} surfaceGenerationChanged=false
    07-03 11:09:45.326 31514-31514/com.blikoon.rooster D/ScrollView: onsize change changed
    07-03 11:09:45.339 31514-31514/com.blikoon.rooster D/ViewRootImpl@66c51fe[LoginActivity]: MSG_WINDOW_FOCUS_CHANGED 0

    • From : 07-03 11:07:40.467 31514-31840/com.blikoon.rooster W/AbstractXMPPConnection: Connection closed with error
      java.net.SocketException: Connection reset, it looks like the server is closing the connection for some reason. If you are sure the credentials you are using are all right, I would try with another client and/or other server. From the results I would be able to pin out what is wrong. Also do you notice the same problem by compiling the code from github? I can’t diagnose the problem without looking at your code. Hope this helps.

  39. Hi! I would like to ask if this is possible for a database (will be getting from http rest api) with a website that does not have xmpp? How would I know if it has xmpp? I am sorry, I am so confused. I’m an intern who was told to create an app based on the website another intern created.

    Was planning to use firebase but the website’s database is not designed for firebase.

    • Sorry for the late reply Karl. I can’t really understand what it is you are trying to achieve. But if you want to communicate from android app to a web based xmpp client , that is very possible. You may know if the website uses xmpp by looking at its source code.

  40. Well…thank you very much, it does exactly what it says.
    is there any way i can get notification when i receive a message?
    and also how can i make this app to login with another account instead of xmpp account?

    • s there any way i can get notification when i receive a message?

      Sure, you can implement the logic to pop up a notification when the a message comes in, have that in mind but haven’t had time to implement that yet.

      how can i make this app to login with another account instead of xmpp account?

      What other account ? Can’t really be of much help without further details.

  41. Hey Man,

    Thanks for this post. It is amazing But how to handle certification of SSL and many more

    • Smack handles ssl certification for you on the client side. You just have to make it required like this

      setSecurityMode(ConnectionConfiguration.SecurityMode.required)

      On the server side, https://letsencrypt.org/ is a good candidate for your xmpp server.

      Hope this is helpful

  42. Awesome Tutorial. I thoroughly enjoyed reading and practicing this project. I am very new android and I got lot of new information from this.

  43. Hi thanks for the tutorial. my problem is that when i click to sign up, the process takes long and the log simply says
    LoginActivity: saveCredentialsAndLogin() called.
    08-16 12:08:45.052 27287-27287/com.ash.mychat D/RoosterService: onStartCommand()
    08-16 12:08:45.052 27287-27287/com.ash.mychat D/RoosterService: Service Start() function called.

    and no other error.
    At times it signs in well. i cant tell why this happens. my internet connection is fast enough. please guide me

    • The login process usually takes long because of the ssl handshake happening between your client and server. It usually takes 10~30 seconds on my environment. But this really depends on your environment. Your connection might be good but your server might be not that fast on responding. But again these are just guesses. You might have to diagnose more to find out what is the problem here.

      Hope this is helpful.

  44. Hi, can you help me.

    I’m using Firebase Google, but I can not connect, you can help me solve this problem.

    Exception.
    10-21 23:19:08.930 30047-30188/com.blikoon.rooster W/System.err: org.jivesoftware.smack.sasl.SASLErrorException: SASLError using X-OAUTH2: not-authorized
    10-21 23:19:08.930 30047-30188/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.SASLAuthentication.authenticationFailed(SASLAuthentication.java:291)
    10-21 23:19:08.940 30047-30188/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1084)
    10-21 23:19:08.940 30047-30188/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:982)
    10-21 23:19:08.940 30047-30206/com.blikoon.rooster I/XMPPTCPConnection: XMPPTCPConnection[not-authenticated] (0) received closing element. Server wants to terminate the connection, calling disconnect()
    10-21 23:19:08.940 30047-30188/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:998)
    10-21 23:19:08.940 30047-30188/com.blikoon.rooster W/System.err: at java.lang.Thread.run(Thread.java:841)
    10-21 23:19:31.860 30047-30556/com.blikoon.rooster I/XMPPTCPConnection: XMPPTCPConnection[not-authenticated] (1) received closing element. Server wants to terminate the connection, calling disconnect()
    10-21 23:19:31.860 30047-30544/com.blikoon.rooster W/System.err: org.jivesoftware.smack.sasl.SASLErrorException: SASLError using X-OAUTH2: not-authorized
    10-21 23:19:31.860 30047-30544/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.SASLAuthentication.authenticationFailed(SASLAuthentication.java:291)
    10-21 23:19:31.860 30047-30544/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1084)
    10-21 23:19:31.860 30047-30544/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$300(XMPPTCPConnection.java:982)
    10-21 23:19:31.870 30047-30544/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:998)
    10-21 23:19:31.870 30047-30544/com.blikoon.rooster W/System.err: at java.lang.Thread.run(Thread.java:841)

    Config

    new AndroidSmackInitializer().initialize();

    XMPPTCPConnection.setUseStreamManagementResumptionDefault(true);
    XMPPTCPConnection.setUseStreamManagementDefault(true);

    SASLAuthentication.registerSASLMechanism(new SASLXOauth2Mechanism() );

    XMPPTCPConnectionConfiguration.Builder conf = XMPPTCPConnectionConfiguration.builder();
    conf.setXmppDomain(“FCM XMPP Client Connection Server”);
    conf.setHostAddress( InetAddress.getByName(GCM_SERVER ));
    conf.setPort(GCM_PORT);

    conf.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled);
    conf.setSendPresence(false);
    conf.setSocketFactory(SSLSocketFactory.getDefault());
    // Launch a window with info about packets sent and received
    conf.setDebuggerEnabled(true);

    setupUiThreadBroadCastMessageReceiver();

    mConnection = new XMPPTCPConnection(conf.build());

    mConnection.addConnectionListener(this);
    try {
    Log.d(TAG, “Calling connect() “);
    mConnection.connect();

    mConnection.login(“#######@gcm.googleapis.com”, “APIIIIIIIIIIIIIIIIIIIIIII”);
    Log.d(TAG, ” login() Called “);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }

    • I haven’t worked with firebase, so I can’t be of much help here. I guess you might get more helpful feedback from firebase specific forums or tutorial.

      Good luck.

    • Thanks Ashu for the input,
      Were you building the code from github ?, I am in the process of updating it and I will consider your suggestion. I still have to find the time to update the tutorial. Happy coding!

  45. Hi ! Firt, i will say thank you for your job, everything work fine, but i got a graphic bug when i receive the message. I got a black line with the content of the message.

    Can you help there ?

  46. Hello,
    Im running the project from the github link.
    and even though I’ve created a user on the web and I changed the host link in the RoosterConnection.java to the host url im working on., i cant seem to log in on my mobile with the error “Something went wrong while connecting ,make sure the credentials are right and try again”.

    What could be the problem here?

    • If I remember correctly File upload is provided by a plugin that was lately developed by the Openfire guys. You have to enable it somehow. I don’t use Openfire personally but you can ask in the “open_chat@conference.igniterealtime.org” MUC and you’ll probably get better advice.

      Good luck.

  47. Hi thanks for the tutorial.
    I ma facing this problem on Oreo

    android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground() at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1775)at android.os.Handler.dispatchMessage(Handler.java:105)

    I have added startForegroundService(intent) in my service onStartCommand method but still showing same error
    Thank you again for the tutorial

  48. Hi,

    I have compiled on Android Studio 3.01 without any problems.

    I registered at xmpp.jp website also without problems .

    What is the error below?
    Trying to connect using your very first login activity I got:

    03-25 20:09:39.011 2708-2708/com.blikoon.rooster D/RoosterService: onCreate()
    03-25 20:09:39.011 2708-2708/com.blikoon.rooster D/RoosterService: onStartCommand()
    03-25 20:09:39.011 2708-2708/com.blikoon.rooster D/RoosterService: Service Start() function called.
    03-25 20:09:39.021 2708-5890/com.blikoon.rooster D/RoosterService: initConnection()
    03-25 20:09:39.021 2708-5890/com.blikoon.rooster D/RoosterConnection: RoosterConnection Constructor called.
    03-25 20:09:39.021 2708-5890/com.blikoon.rooster D/RoosterConnection: Connecting to server xmpp.jp
    03-25 20:09:39.021 2708-5890/com.blikoon.rooster D/RoosterConnection: Username : username
    03-25 20:09:39.021 2708-5890/com.blikoon.rooster D/RoosterConnection: Password : alteredforsecurity
    03-25 20:09:39.021 2708-5890/com.blikoon.rooster D/RoosterConnection: Server : xmpp.jp
    03-25 20:09:39.031 2708-5890/com.blikoon.rooster D/RoosterConnection: Calling connect()
    03-25 20:10:10.661 2708-5890/com.blikoon.rooster D/RoosterService: Something went wrong while connecting ,make sure the credentials are right and try again
    03-25 20:10:10.661 2708-5890/com.blikoon.rooster W/System.err: org.jivesoftware.smack.XMPPException$StreamErrorException: host-unknown You can read more about the meaning of this stream error at http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions
    03-25 20:10:10.661 2708-5890/com.blikoon.rooster W/System.err:
    03-25 20:10:10.661 2708-5890/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1053)org.jivesoftware.smack.XMPPException$StreamErrorException: host-unknown You can read more about the meaning of this stream error at http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions
    03-25 20:05:15.751 2708-5451/com.blikoon.rooster W/System.err:
    03-25 20:05:15.751 2708-5451/com.blikoon.rooster W/System.err: at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:1053)

  49. Hi Akhilesh,
    Are you logging in from two different devices, with two different userid’s
    because it is not working for me. And i am using smack 4.3,please help me.

    Thanks in advance

  50. HI Daniel,
    Thanks for the tutorial, they are working nice but the incomingchatmessagelistener is not working for received messages ,while message are sent succesfully. I am using smack 4.3 can you please suggest where am i going wrong. I am using your last committed code on github.

  51. Hi Daniel,
    Your tutorials are good, but the incomingmessagelistener is not working in the latest committed code.Can you please check it, it will be very helpful for me.
    Thank you in advance

  52. Hi,

    I have a question, does this client app connects with any xxmp server or specific server.

    Reading through this owesome tutorial, I am unable to see the specific parameters that the app use to connect to a specific server, parameters such as servername, port, etc.

    Once again thanks for the tutorial.

  53. Hi!
    I’m developing my own chat application which will work offline in my local server.
    And everything except chatting is done. I store every user’s information in my database.
    And now I have a trouble with chatting.
    After reading your tutorial I understand that you do not use any specific servers or smth like that.
    Could you possibly say me if I follow this tutorial will I have acces to send messages locally(offfline)?

  54. I found error on this section. please help me
    public void connect() throws IOException,XMPPException,SmackException
    {
    Log.d(TAG, “Connecting to server ” + mServiceName);
    XMPPTCPConnectionConfiguration.Builder builder=
    XMPPTCPConnectionConfiguration.builder();
    builder.setServiceName(mServiceName);//error
    builder.setUsernameAndPassword(mUsername, mPassword);
    builder.setRosterLoadedAtLogin(true);// canot resolve the method
    builder.setResource(“Rooster”);

    //Set up the ui thread broadcast message receiver.
    //setupUiThreadBroadCastMessageReceiver();

    mConnection = new XMPPTCPConnection(builder.build());
    mConnection.addConnectionListener(this);
    mConnection.connect();
    mConnection.login();

    ReconnectionManager reconnectionManager = ReconnectionManager.getInstanceFor(mConnection);
    reconnectionManager.setEnabledPerDefault(true);
    reconnectionManager.enableAutomaticReconnection();

  55. Hello everyone !
    I am new in XMPP . Need your help Daniel and anyone else who has encountered it before . When I run the app nothing happens . Like @Priya my app is also causing issues and here
    Log.d(TAG, “Connecting to server ” + mServiceName);
    XMPPTCPConnectionConfiguration.Builder builder=
    XMPPTCPConnectionConfiguration.builder();
    builder.setServiceName(mServiceName);//error
    builder.setUsernameAndPassword(mUsername, mPassword);
    builder.setRosterLoadedAtLogin(true);// canot resolve the method
    builder.setResource(“Rooster”);

    //Set up the ui thread broadcast message receiver.
    //setupUiThreadBroadCastMessageReceiver();

    mConnection = new XMPPTCPConnection(builder.build());
    mConnection.addConnectionListener(this);
    mConnection.connect();
    mConnection.login();

    I got 2 errors :
    1 : Must have XMPP Domain at the mService . Can anyone let why it is so?
    2 : And setRosterLoadedAtLogin(true) is marked .

    Any help will be great !

  56. Hello Everyone mService is giving an exception shows as Must have a XMPP Domain . So whats the issue and how will we get the server name or domain . I had openfire server installed as me at admin and a user as well but still when I can app nothing is happening it crashes and ask for domain name

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.