ysfcyln
ysfcyln

Reputation: 3105

Android Window Manager block system back key

I have an floating view like Facebook chat buble, but unlike it, my overlay has a EditText and need to be focusable.

Here is my floating view code

        //Inflate the floating view layout we created
        mFloatingView = 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_TOUCH_MODAL,
                PixelFormat.TRANSLUCENT);

        //Specify the view position
        params.gravity = Gravity.TOP | Gravity.START;        //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(mFloatingView, params);

It is almost okey but there is a problem. When I create overlay from service, System Back Button not working. If I use FLAG_NOT_FOCUSABLE System buttons; home, recents and back works as expected. I made some research at SO and find out that it is a security issue so I started to find alternative solutions and found this then changed my code

// Wrapper for intercepting System/Hardware key events
ViewGroup wrapper = new FrameLayout(this) {
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) {
            Log.v("Back", "Back Key");
            return true;
        }
        return super.dispatchKeyEvent(event);
    }
};

//Inflate the floating view layout we created
mFloatingView = LayoutInflater.from(this).inflate(R.layout.floating_widget_layout, wrapper);

//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_TOUCH_MODAL,
        PixelFormat.TRANSLUCENT);

//Specify the view position
params.gravity = Gravity.TOP | Gravity.START;        //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(mFloatingView, params);

Now I can get back press from my floating view but how can I pass this event(back press) to the foreground app(other app, not mine) ? I found this but it didn't help me

If someone can help me or at least give a clue, I will be appreciate

Summary

I have an overlay view, it needs to be focusable, but back press button not working when it is focusable how I can solve this?

Upvotes: 7

Views: 1942

Answers (2)

vasyl
vasyl

Reputation: 105

Solution: to intercept KeyEvent events and use them in WindowManager you have to use FLAG_NOT_TOUCH_MODAL which allows to collect them. Unfortunately this flag doesn't let these events further so pressing back button won't trigger its regular function. To get rid of that problem simply remove view added to WindowManager after running the code that you want to use on back press event.

This solution removes the view which might be an obvious disadvantage in some cases.

Example (works well in Service):

    private void addView() {
        WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        LayoutInflater li = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        WindowManager.LayoutParams parameters = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
                PixelFormat.TRANSLUCENT
        );
        parameters.gravity = Gravity.TOP | Gravity.START;
        FrameLayout wrapper = new FrameLayout(this) {
            @Override
            public boolean dispatchKeyEvent(KeyEvent event) {
                if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
                    System.out.println("Back pressed");
                    // do something
                    view.setVisibility(View.GONE); // removing view allows back press go through
                    return super.dispatchKeyEvent(event);
                }
                return super.dispatchKeyEvent(event);
            }
            
            public void onCloseSystemDialogs(String reason) {
                if (reason.equals("homekey")) {
                    System.out.println("Home button pressed");
                    // do something
                }
            }
        };                
        View view = li.inflate(R.layout.your_layout, wrapper);                
        view.requestFocus();
        view.setFocusable(true);
        view.setFocusableInTouchMode(true);
        wm.addView(view, parameters);
    }

Upvotes: 0

ptgr
ptgr

Reputation: 11

This tutorial seems to have a solution: https://www.geeksforgeeks.org/how-to-make-a-floating-window-application-in-android/

They set FLAG_NOT_FOCUSABLE initially so that the overlay doesn't interfere with system back function, etc. They set onTouch listener on the EditText and update the flag to FLAG_NOT_TOUCH_MODAL at that point so that text could be entered.

Upvotes: -1

Related Questions