Please enable JavaScript to view the comments powered by Disqus.

Floating View like Facebook Chatheads

In this post, I’ll show you how to create a floating view like Facebook chatheads - the view that was drawn on top of other applications.
So, the very first question is: How can we do that? An activity with transparent background?
Actually, there’s no activity here. Instead, we’ll user service!

As you know, activity and dialog have their own Window instance which provides standard UI policies such as a background, title area, default key processing, etc.

Even the service has Window! So, the solution here is that we will use the service’s Window to draw our desired view (that can be overlay on other application!).

In order to do that, you have to follow below steps:

1 - Add permission

Open AndroidManifest.xml file and add the below permission:

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

Regards to Android documents:

Allows an application to open windows using the type TYPE_SYSTEM_ALERT, shown on top of all other applications. Very few applications should use this permission; these windows are intended for system-level interaction with the user.

2 - Create Floating View Service

Create a class called FloatingViewService that extends Service, contains Window instance and a FrameLayout object used to display your view:

public class FloatingViewService extends Service {

    private WindowManager mWindowManager;
    private FrameLayout mFrameLayout;

    @Override
    public IBinder onBind(Intent intent) {
        //Not use this method
        return null;
    }

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

    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }
}

Inside onCreate method, we just need to set up the view with the corresponding layout params and finally call WindowManager.addView():

mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.TYPE_PHONE,
        WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
        PixelFormat.TRANSLUCENT);

params.gravity = Gravity.TOP | Gravity.LEFT;

mFrameLayout = new FrameLayout(context);

mWindowManager.addView(mFrameLayout, params);

LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
// Here is the place where you can inject whatever layout you want.
layoutInflater.inflate(R.layout.head, mFrameLayout);

Please note that 3 attributes below are mandatory for floating view:

Don’t forget to declare FloatingViewService in the AndroidManifest.xml file:

<service android:name=".FloatingViewService" />

Finally, start the service to trigger your floating view:

startService(new Intent(getApplicationContext(), FloatingViewService.class));

 3 - Demo Floating View like Facebook Chatheads

The first two sections showed you how to implement floating view like Facebook Chatheads. In this section, I’ll make a very simple application to demonstrate it.

The view in this application will be an ImageView that you can drag around.

Firstly, create an activity with a Button that allows you to turn on/off the floating view:

<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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.icetea09.demofloatingview.MainActivity">

    <Button
        android:id="@+id/btn_show_floating_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Show Floating View"/>

</RelativeLayout>

Then, create FloatingViewService:

package com.icetea09.demofloatingview;

import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;

public class FloatingViewService extends Service {

    private WindowManager mWindowManager;
    private ImageView mImgFloatingView;
    private boolean mIsFloatingViewAttached = false;

    @Override
    public IBinder onBind(Intent intent) {
        //Not use this method
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if(!mIsFloatingViewAttached){
            mWindowManager.addView(mImgFloatingView, mImgFloatingView.getLayoutParams());
        }
        return super.onStartCommand(intent, flags, startId);
    }

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

        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

        mImgFloatingView = new ImageView(this);
        mImgFloatingView.setImageResource(R.mipmap.ic_launcher);

        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                PixelFormat.TRANSLUCENT);

        params.gravity = Gravity.TOP | Gravity.LEFT;

        mWindowManager.addView(mImgFloatingView, params);

        mIsFloatingViewAttached = true;
    }

    public void removeView() {
        if (mImgFloatingView != null){
            mWindowManager.removeView(mImgFloatingView);
            mIsFloatingViewAttached = false;
        }
    }

    @Override
    public void onDestroy() {
        Toast.makeText(getApplicationContext(), "onDestroy", Toast.LENGTH_SHORT);
        super.onDestroy();
        removeView();
    }
}

To be able to drag the “chatheads” around, you need to handle the OnTouchListener of the ImageView:

mImgFloatingView.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:
                        initialX = params.x;
                        initialY = params.y;
                        initialTouchX = event.getRawX();
                        initialTouchY = event.getRawY();
                        return true;
                    case MotionEvent.ACTION_UP:
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        params.x = initialX + (int) (event.getRawX() - initialTouchX);
                        params.y = initialY + (int) (event.getRawY() - initialTouchY);
                        mWindowManager.updateViewLayout(mImgFloatingView, params);
                        return true;
                }
                return false;
            }
        });

In the MainActivity, we handle the Button clicked event to show or hide floating view:

public class MainActivity extends ActionBarActivity implements View.OnClickListener{

    private Button mBtnShowView;
    private boolean mIsFloatingViewShow; //Flag variable used to identify if the Floating View is visible or not

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mBtnShowView = (Button)findViewById(R.id.btn_show_floating_view);
        mBtnShowView.setOnClickListener(this);
        mIsFloatingViewShow = false;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.btn_show_floating_view:
                if(mIsFloatingViewShow){
                    hideFloatingView();
                    mIsFloatingViewShow = false;
                    mBtnShowView.setText(R.string.show_floating_view);
                }
                else{
                    showFloatingView();
                    mIsFloatingViewShow = true;
                    mBtnShowView.setText(R.string.hide_floating_view);
                }
                break;
        }
    }

    private void showFloatingView() {
        startService(new Intent(getApplicationContext(), FloatingViewService.class));
    }

    private void hideFloatingView() {
        stopService(new Intent(getApplicationContext(), FloatingViewService.class));
    }

}

Finally, run the demo application and enjoy the result:

4 - Source Code Floating View like Facebook Chatheads

https://github.com/trinhlbk1991/DemoAndroidFloatingView