Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to detect backbutton/home press from a service like messenger chat head service?

I have been looking through several stackoverflow question to find out how can I listen to backpress button on a service using windows manager. Most of the answers proposes that it's not possible, however I can see that messenger handle it very well.

How does messenger handle the backpress button on it's head chat service? (Or I am completely wrong and they are not a service using windows manager?)

like image 619
TSR Avatar asked Mar 15 '17 22:03

TSR


1 Answers

To achieve what you need, you need to extend some ViewGroup that you are going to use as a root container for your views. Let's start with this:

public class BackButtonAwareLinearLayout extends LinearLayout {

    public interface BackButtonListener {
        void onBackButtonPressed();
    }

    @Nullable
    private BackButtonListener mListener;

    public BackButtonAwareLinearLayout(Context context) {
        super(context);
    }

    public BackButtonAwareLinearLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public BackButtonAwareLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public void setBackButtonListener(@Nullable BackButtonListener listener) {
        mListener = listener;
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK
                && mListener != null) {
            mListener.onBackButtonPressed();
            return true;
        }
        return super.dispatchKeyEvent(event);
    }
}

Basically, overriding dispatchKeyEvent is what does a trick for us here. Then make a use of it in some xml (I have called it chat_head_container.xml):

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

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="48sp"
        android:text="Hello, world!"
        android:textColor="#000"
        android:background="#f5f5f5"
        android:gravity="center"/>

</com.pablo432.myapplication.BackButtonAwareLinearLayout>

Next, create a Service that adds our view to the WindowManager (though I suppose you know how to do it, I'll post it anyway for the sake of completeness):

public class ChatHeadService extends Service
        implements BackButtonAwareLinearLayout.BackButtonListener {

    private WindowManager mWindowManager;
    private BackButtonAwareLinearLayout mRootContainer;

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

    @Override
    public void onCreate() {
        super.onCreate();
        mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mRootContainer = (BackButtonAwareLinearLayout) inflater.inflate(
                R.layout.chat_head_container, null, false);
        mRootContainer.setBackButtonListener(this);

        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.MATCH_PARENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_FULLSCREEN,
                PixelFormat.TRANSPARENT);

        mWindowManager.addView(mRootContainer, layoutParams);
    }

    @Override
    public void onBackButtonPressed() {
        mRootContainer.setBackButtonListener(null);
        mWindowManager.removeView(mRootContainer);
    }

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

So long story short, BackButtonAwareLinearLayout exposes a listener interface, that our service needs to implement and subscribe itself to the Layout.

Also have in mind that this addresses handling back button. To handle home button, you may want to take a look at https://stackoverflow.com/a/31340960 and https://stackoverflow.com/a/33580971 - basically my answer is a bit of a summary from those two links + https://stackoverflow.com/a/15980900 but contains few tweaks (like, for example, you can't set FLAG_NOT_FOCUSABLE in WindowManager.LayoutParams).

Of course you need to start your service somewhere by calling startService, declare this service in AndroidManifest.xml and add a SYSTEM_ALERT_WINDOW permission.

like image 161
pablo432 Avatar answered Nov 10 '22 19:11

pablo432