Rapid Subscribe Android App

Rapid Subscribe Android App
Rapid Subscriber

Recent Posts

Facebook like Chat Heads in Android App | Overlay Layout

Facebook like Chat Heads in Android App | Overlay Layout







Facebook chat heads are used for multi-tasking of chatting with friends use another app also. Facebook Chat Heads are bubbles shown on screen side to open and send messages without interrupting any other app usage you used simultaneously.

Facebook like Chat Heads android preview overlay

Facebook like Chat Heads android preview

Some points to remember when creating chat heads.
  • System Alert Window permission in Android Manifest (draw over other apps)
  • Request runtime permission to draw over other apps.
  • Create a custom layout of chat heads
  • Create a Service class to handle functionality of chat heads icon click and open, close of chat head.


So, Without any extra talk, Let's Start creating.

Create an Android Project, open Android Manifest.xml

Write permission in AndroidManifest.xml
 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />  




Runtime Permission request is used from Android Marshmallow(6.0), before Android M this permission is given by default.

To request other permissions, you can see this post, but for Draw over other apps permission, we will change our request criteria to get this permission.

After you learn how to add and request runtime permission, further we create our Overlay layout of Chat Heads, Also we open chat heads and on expanded view of chat head we will show a music player menu to learn the functionality of chat heads expand and collapsed and also clicking on chat heads icons.

We will use some icons to show in our Chat heads layout. You can download here any of your usable icons according to your app requirements.

Overlay Layout(Chat Heads Layout)
 <?xml version="1.0" encoding="utf-8"?>  
 <FrameLayout  
   xmlns:android="http://schemas.android.com/apk/res/android"  
   xmlns:tools="http://schemas.android.com/tools"  
   android:layout_width="wrap_content"  
   android:layout_height="wrap_content">  
   <!--Root container-->  
   <RelativeLayout  
     android:id="@+id/root_container"  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     tools:ignore="UselessParent">  
     <!--View while view is collapsed-->  
     <RelativeLayout  
       android:id="@+id/collapse_view"  
       android:layout_width="wrap_content"  
       android:visibility="visible"  
       android:layout_height="wrap_content"  
       android:orientation="vertical">  
       <!--Icon of floating widget -->  
       <ImageView  
         android:id="@+id/collapsed_iv"  
         android:layout_width="60dp"  
         android:layout_height="60dp"  
         android:layout_marginTop="8dp"  
         android:src="@drawable/ic_android_circle"  
         tools:ignore="ContentDescription"/>  
       <!--Close button-->  
       <ImageView  
         android:id="@+id/close_btn"  
         android:layout_width="20dp"  
         android:layout_height="20dp"  
         android:layout_marginLeft="40dp"  
         android:src="@drawable/ic_close_black_24dp"  
         tools:ignore="ContentDescription"/>  
     </RelativeLayout>  
     <!--View while view is expanded-->  
     <LinearLayout  
       android:id="@+id/expanded_container"  
       android:layout_width="wrap_content"  
       android:layout_height="wrap_content"  
       android:background="#F8BBD0"  
       android:visibility="gone"  
       android:orientation="horizontal"  
       android:padding="8dp">  
       <ImageView  
         android:layout_width="80dp"  
         android:layout_height="80dp"  
         android:src="@drawable/ic_android_circle"  
         tools:ignore="ContentDescription"/>  
       <ImageView  
         android:id="@+id/prev_btn"  
         android:layout_width="30dp"  
         android:layout_height="30dp"  
         android:layout_gravity="center_vertical"  
         android:layout_marginLeft="20dp"  
         android:src="@drawable/ic_chevron_left_black_24dp"  
         tools:ignore="ContentDescription"/>  
       <ImageView  
         android:id="@+id/play_btn"  
         android:layout_width="50dp"  
         android:layout_height="50dp"  
         android:layout_gravity="center_vertical"  
         android:layout_marginLeft="10dp"  
         android:src="@drawable/ic_play_arrow_black_24dp"  
         tools:ignore="ContentDescription"/>  
       <ImageView  
         android:id="@+id/next_btn"  
         android:layout_width="30dp"  
         android:layout_height="30dp"  
         android:layout_gravity="center_vertical"  
         android:layout_marginLeft="10dp"  
         android:src="@drawable/ic_chevron_right_black_24dp"  
         tools:ignore="ContentDescription"/>  
       <RelativeLayout  
         android:layout_width="wrap_content"  
         android:layout_height="match_parent"  
         android:orientation="vertical">  
         <ImageView  
           android:id="@+id/close_button"  
           android:layout_width="20dp"  
           android:layout_height="20dp"  
           android:src="@drawable/ic_close_black_24dp"/>  
         <ImageView  
           android:id="@+id/open_button"  
           android:layout_width="20dp"  
           android:layout_height="20dp"  
           android:layout_alignParentBottom="true"  
           android:src="@drawable/ic_add_black_24dp"/>  
       </RelativeLayout>  
     </LinearLayout>  
   </RelativeLayout>  
 </FrameLayout>  

In this we create both layouts and changes visibility accordingly with our app design. When you understand the layout and its functionality, you can use it in your own way.

After that, we will create a Service Class to handle functionality and clicks of our chat head and its icons.

Service Class
 package studio.harpreet.sampleproject;  
 import android.app.Service;  
 import android.content.Intent;  
 import android.graphics.PixelFormat;  
 import android.opengl.Visibility;  
 import android.os.IBinder;  
 import android.view.Gravity;  
 import android.view.LayoutInflater;  
 import android.view.MotionEvent;  
 import android.view.View;  
 import android.view.WindowManager;  
 import android.widget.ImageView;  
 import android.widget.Toast;  
 public class OverlayShowingService extends Service {  
   private WindowManager mWindowManager;  
   private View mFloatingView;  
   @Override  
   public IBinder onBind(Intent intent) {  
     return null;  
   }  
   @Override  
   public void onCreate() {  
     super.onCreate();  
     mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);  
     mFloatingView = LayoutInflater.from(OverlayShowingService.this).inflate(R.layout.overlay_layout,null );  
     int LAYOUT_FLAG;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
        }
        //Add the view to the window.
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                LAYOUT_FLAG,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT); 
     //Specify the view position  
     params.gravity = Gravity.TOP | Gravity.LEFT;    //Initially view will be added to top-left corner  
     params.x = 0;  
     params.y = 0;  
     //Add the view to the window  
     //  mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);  
     mWindowManager.addView(mFloatingView, params);  
     //The root element of the collapsed view layout  
     final View collapsedView = mFloatingView.findViewById(R.id.collapse_view);  
     //The root element of the expanded view layout  
     final View expandedView = mFloatingView.findViewById(R.id.expanded_container);  
     //Set the close button  
     ImageView closeButtonCollapsed = (ImageView) mFloatingView.findViewById(R.id.close_btn);  
     closeButtonCollapsed.setOnClickListener(new View.OnClickListener() {  
       @Override  
       public void onClick(View view) {  
         //close the service and remove the from from the window  
         stopSelf();  
       }  
     });  
     //Set the view while floating view is expanded.  
     //Set the play button.  
     ImageView playButton = (ImageView) mFloatingView.findViewById(R.id.play_btn);  
     playButton.setOnClickListener(new View.OnClickListener() {  
       @Override  
       public void onClick(View v) {  
         Toast.makeText(OverlayShowingService.this, "Playing the song.", Toast.LENGTH_LONG).show();  
       }  
     });  
     //Set the next button.  
     ImageView nextButton = (ImageView) mFloatingView.findViewById(R.id.next_btn);  
     nextButton.setOnClickListener(new View.OnClickListener() {  
       @Override  
       public void onClick(View v) {  
         Toast.makeText(OverlayShowingService.this, "Playing next song.", Toast.LENGTH_LONG).show();  
       }  
     });  
     //Set the pause button.  
     ImageView prevButton = (ImageView) mFloatingView.findViewById(R.id.prev_btn);  
     prevButton.setOnClickListener(new View.OnClickListener() {  
       @Override  
       public void onClick(View v) {  
         Toast.makeText(OverlayShowingService.this, "Playing previous song.", Toast.LENGTH_LONG).show();  
       }  
     });  
     //Set the close button  
     ImageView closeButton = (ImageView) mFloatingView.findViewById(R.id.close_button);  
     closeButton.setOnClickListener(new View.OnClickListener() {  
       @Override  
       public void onClick(View view) {  
         collapsedView.setVisibility(View.VISIBLE);  
         expandedView.setVisibility(View.GONE);  
       }  
     });  
     //Open the application on thi button click  
     ImageView openButton = (ImageView) mFloatingView.findViewById(R.id.open_button);  
     openButton.setOnClickListener(new View.OnClickListener() {  
       @Override  
       public void onClick(View view) {  
         //Open the application click.  
         Intent intent = new Intent(OverlayShowingService.this, MainActivity.class);  
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
         startActivity(intent);  
         //close the service and remove view from the view hierarchy  
         stopSelf();  
       }  
     });  
     //Drag and move floating view using user's touch action.  
     mFloatingView.findViewById(R.id.root_container).setOnTouchListener(new View.OnTouchListener() {  
       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();  
             return true;  
           case MotionEvent.ACTION_UP:  
             int Xdiff = (int) (event.getRawX() - initialTouchX);  
             int Ydiff = (int) (event.getRawY() - initialTouchY);  
             //The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little while clicking.  
             //So that is click event.  
             if (Xdiff < 10 && Ydiff < 10) {  
               if (isViewCollapsed()) {  
                 //When user clicks on the image view of the collapsed layout,  
                 //visibility of the collapsed layout will be changed to "View.GONE"  
                 //and expanded view will become visible.  
                 collapsedView.setVisibility(View.GONE);  
                 expandedView.setVisibility(View.VISIBLE);  
               }  
             }  
             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(mFloatingView, params);  
             return true;  
         }  
         return false;  
       }  
     });  
   }  
   /**  
    * Detect if the floating view is collapsed or expanded.  
    *  
    * @return true if the floating view is collapsed.  
    */  
   private boolean isViewCollapsed() {  
     return mFloatingView == null || mFloatingView.findViewById(R.id.collapse_view).getVisibility() == View.VISIBLE;  
   }  
   @Override  
   public void onDestroy() {  
     super.onDestroy();  
     if (mFloatingView != null) mWindowManager.removeView(mFloatingView);  
   }  
 }  

Here, we handle all functionality of our chat head and its icons. Also we get view expanded or closed function.

  • Stop self closes the service class.
  • If our app runs on device < Android Oreo, then we use Type application phone instead we use Type application Overlay
  • When starting any activity from the service class (from chat head) then you should call stop self to stop the service to avoid overlay problems.
Now after all that, we will create our XML activity with one button to start our Service class on a button click.

XML activity
 <?xml version="1.0" encoding="utf-8"?>  
 <LinearLayout 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="match_parent"  
   android:layout_height="match_parent"  
   android:orientation="vertical"  
   tools:context=".ChatHead">  
   <Button  
     android:layout_width="wrap_content"  
     android:layout_height="wrap_content"  
     android:text="Show Chat Heads"  
     android:id="@+id/show_chat_head_btn"/>  
 </LinearLayout>  

In our Java activity, we will start our service class and close our activity, you can start both also by not calling finish on activity.

Java Activity
 package studio.harpreet.sampleproject;  
 import android.content.Intent;  
 import android.os.Bundle;  
 import android.view.View;  
 import android.widget.Button;  
 import androidx.appcompat.app.AppCompatActivity;  
 public class ChatHead extends AppCompatActivity {  
 Button btn;  
   @Override  
   protected void onCreate(Bundle savedInstanceState) {  
     super.onCreate(savedInstanceState);  
     setContentView(R.layout.activity_chat_head);  
     btn = findViewById(R.id.show_chat_head_btn);  
     btn.setOnClickListener(new View.OnClickListener() {  
       @Override  
       public void onClick(View v) {  
       if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {  
           if(Settings.canDrawOverlays(NextActivity.this))  
           {  
             startService(new Intent(ChatHead.this,OverlayShowingService.class));  
           	finish();   
           }  
           else  
           {  
             Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:"+getPackageName()));  
             Toast.makeText(NextActivity.this, "Please Give Permission to Draw over other apps", Toast.LENGTH_SHORT).show();  
             startActivity(intent);  
           }  
         }
       }  
     });  
   }  
 }  

Now, on a button click, our chat heads are open and we will see the expanded and closed chat heads. You can create your own functionality on this according to your app design.


Follow us for more posts like this, 
Subscribe to Harpreet studio on Youtube  
Like Harpreet Studio on Facebook  
Follow me on Instagram 

No comments