Home / Programming / Android / How to Create Chat Heads Like Facebook Messenger on Android

How to Create Chat Heads Like Facebook Messenger on Android

In this tutorial, we are going to learn how to create simple chat head that allow users to drag them across the screen and then launch the App by tapping on it – the Floating Widget – just like Facebook messenger.

Step 1

Add android.permission.SYSTEM_ALERT_WINDOW Permission to Your Android Manifest.

<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.app_name">

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

    <application
      ...
    </application>

</manifest>

Reason:  Chat heads are nothing but a floating views that is drawn over other applications. Android system allows applications to draw over other application if the application has android.permission.SYSTEM_ALERT_WINDOW permission. We are going to use the background service to add the floating widget into the view hierarchy of the current screen. So, this floating view is always on top of application windows.

Step 2

Create the layout of the chat head you want to display –  floating_widget_layout.xml

<android.support.constraint.ConstraintLayout
 xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="wrap_content"
 android:id="@+id/root_container"
 android:layout_height="wrap_content">

 <ImageView
   android:id="@+id/app_logo"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_marginTop="8dp"
   android:src="@mipmap/ic_launcher_round"
   app:layout_constraintTop_toTopOf="parent"/>

 <ImageView
   android:id="@+id/close_floating_view"
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_marginStart="45dp"
   android:layout_marginLeft="45dp"
   android:layout_marginTop="4dp"
   android:background="@drawable/circle_shape"
   android:src="@drawable/ic_close_white_24dp"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toTopOf="parent"
   tools:ignore="ContentDescription"/>

</android.support.constraint.ConstraintLayout>

Add the Following to the drawable resource folder :

circle_shape.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="#000000"/>
</shape>

ic_close_white_24dp.xml

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportHeight="24.0"
        android:viewportWidth="24.0">
    <path
        android:fillColor="#FFFFFFFF"
        android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z" />
</vector>

Step 3

create a service called FloatingWidgetService.

public class FloatingWidgetService extends Service {
   private WindowManager mWindowManager;
   private View mChatHeadView;


   public FloatingWidgetService() {}

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

   @Override
   public void onCreate() {
       super.onCreate();
       //Inflate the chat head layout we created
       mChatHeadView = LayoutInflater.from(this).inflate(R.layout.floating_widget_layout, null);

       //Add the view to the window.
       final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
               WindowManager.LayoutParams.WRAP_CONTENT,
               WindowManager.LayoutParams.WRAP_CONTENT,
               WindowManager.LayoutParams.TYPE_PHONE,
               WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
               PixelFormat.TRANSLUCENT);
      
       //Specify the chat head position
//Initially view will be added to top-left corner
       params.gravity = Gravity.TOP | Gravity.LEFT;
       params.x = 0;          
       params.y = 100;
      
       //Add the view to the window
       mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
       mWindowManager.addView(mChatHeadView, params);
   }


   @Override
   public void onDestroy() {
       super.onDestroy();
       if (mChatHeadView != null) mWindowManager.removeView(mChatHeadView);
   }
}

Whenever you want to display a chat head, start the service using startService() command. In onCreate() of the service we will add the layout of the chat head at the top-left corner of the window.

Step 4

To drag the chat head along with the user’s touch, we have to override OnTouchListener(). Whenever the user touches the chat head, we will record the initial x and y coordinates, and when the user moves the finger, the application will calculate the new X and Y coordinate and move the chat head.

@Override
public void onCreate() {
super.onCreate();

...
...
...
final ImageView chatHeadImage = (ImageView) mChatHeadView.findViewById(R.id.app_logo);
chatHeadImage.setOnTouchListener(new View.OnTouchListener() {
    private int lastAction;
    private int initialX;
    private int initialY;
    private float initialTouchX;
    private float initialTouchY;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:

                //remember the initial position.
                initialX = params.x;
                initialY = params.y;

                //get the touch location
                initialTouchX = event.getRawX();
                initialTouchY = event.getRawY();

                lastAction = event.getAction();
                return true;
            case MotionEvent.ACTION_UP:
                //As we implemented on touch listener with ACTION_MOVE,
                //we have to check if the previous action was ACTION_DOWN
                //to identify if the user clicked the view or not.
                if (lastAction == MotionEvent.ACTION_DOWN) {
                    //Open the chat conversation click.
                    Intent intent = new Intent(ChatHeadService.this, ChatActivity.class);
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    startActivity(intent);

                    //close the service and remove the chat heads
                    stopSelf();
                }
                lastAction = event.getAction();
                return true;
            case MotionEvent.ACTION_MOVE:
                //Calculate the X and Y coordinates of the view.
                params.x = initialX + (int) (event.getRawX() - initialTouchX);
                params.y = initialY + (int) (event.getRawY() - initialTouchY);

                //Update the layout with new X & Y coordinate
                mWindowManager.updateViewLayout(mChatHeadView, params);
                lastAction = event.getAction();
                return true;
        }
        return false;
    }
});
}

Step 5

So finally your FloatingWidgetService.java will look like below:

public class FloatingWidgetService extends Service {

    private WindowManager mWindowManager;
    private View mChatHeadView;

    public FloatingWidgetService() {
    }

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

    @Override
    public void onCreate() {
        super.onCreate();
        //Inflate the chat head layout we created
        mChatHeadView = LayoutInflater.from(this).inflate(R.layout.floating_widget_layout, null);

        //Add the view to the window.
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);

        //Specify the chat head position
        params.gravity = Gravity.TOP | Gravity.LEFT;        //Initially view will be added to top-left corner
        params.x = 0;
        params.y = 100;

        //Add the view to the window
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mWindowManager.addView(mChatHeadView, params);

        //Set the close button.
        ImageView closeButton = (ImageView) mChatHeadView.findViewById(R.id.close_btn);
        closeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //close the service and remove the chat head from the window
                stopSelf();
            }
        });

        //Drag and move chat head using user's touch action.
        final ImageView chatHeadImage = (ImageView) mChatHeadView.findViewById(R.id.app_logo);
        chatHeadImage.setOnTouchListener(new View.OnTouchListener() {
            private int lastAction;
            private int initialX;
            private int initialY;
            private float initialTouchX;
            private float initialTouchY;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:

                        //remember the initial position.
                        initialX = params.x;
                        initialY = params.y;

                        //get the touch location
                        initialTouchX = event.getRawX();
                        initialTouchY = event.getRawY();

                        lastAction = event.getAction();
                        return true;
                    case MotionEvent.ACTION_UP:
                        //As we implemented on touch listener with ACTION_MOVE,
                        //we have to check if the previous action was ACTION_DOWN
                        //to identify if the user clicked the view or not.
                        if (lastAction == MotionEvent.ACTION_DOWN) {
                            //Open the chat conversation click.
                            Intent intent = new Intent(ChatHeadService.this, ChatActivity.class);
                            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);

                            //close the service and remove the chat heads
                            stopSelf();
                        }
                        lastAction = event.getAction();
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        //Calculate the X and Y coordinates of the view.
                        params.x = initialX + (int) (event.getRawX() - initialTouchX);
                        params.y = initialY + (int) (event.getRawY() - initialTouchY);

                        //Update the layout with new X & Y coordinate
                        mWindowManager.updateViewLayout(mChatHeadView, params);
                        lastAction = event.getAction();
                        return true;
                }
                return false;
            }
        });
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mChatHeadView != null) mWindowManager.removeView(mChatHeadView);
    }
}

 

 

About Edge Developer

Hey there! am Opeyemi Olorunleke (aka Edge Developer), an Android developer. I Love Sharing Android Tutorials and code snippets.

Check Also

Android Admob Consent SDK : All you need to know + Example

First of all, let me address Google’s complacency to help app developers implement the GDPR …

Leave a Reply

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