Question

I like to develop an app that is similar to Swapps .i am trying to display a button on top of any screen and that should occur only on a swiping action.I tried with the below code

    WindowManager.LayoutParams params = new WindowManager.LayoutParams();
    params.type =WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
    params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
    params.format =PixelFormat.TRANSLUCENT; 
    params.height = WindowManager.LayoutParams.WRAP_CONTENT;
    params.width = WindowManager.LayoutParams.WRAP_CONTENT;
    parentlay = new LinearLayout(this);
    mybt = new Button(getApplicationContext());
    bt.setText("Click to Go");

    parentlay.setBackgroundColor(Color.TRANSPARENT);
    parentlay.setHapticFeedbackEnabled(true);
    parentlay.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
                // event.getAction() prints 4 and not able to get up or down event
           }
       });
   windowmanager.addView(parentlay, params);

I am trying to display the button when user swipes from left-to-right by capturing that event and doing

    parentlay.addView(bt);

and remove the view when user swipes from right-to-left by

    parentlay.removeView(bt);

As mentioned i coudn't get the motion events unless i changed the type as TYPE_SYSTEM_ALERT ,but that inturn freezes all the screen and could not click back or home button,is there is any alternate way to do this.

I have just tried below modification

    params.type =WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
    params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
    |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
   |WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

    params.height = WindowManager.LayoutParams.MATCH_PARENT;
    params.width = WindowManager.LayoutParams.MATCH_PARENT;

But i couldn't click the underneath button ,may be its due to MATCH_PARTENT but if i set it to wrap_content then i cannot get click events.

Was it helpful?

Solution

To hide the view you need to call mWindowManager.removeView(mOverlay);

private RelativeLayout mOverlay;
        private WindowManager mWindowManager;   
     WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                        WindowManager.LayoutParams.WRAP_CONTENT,
                        WindowManager.LayoutParams.WRAP_CONTENT,
                        WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                                | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
                        PixelFormat.TRANSLUCENT);
                params.gravity = Gravity.TOP;
                LayoutInflater inflater = (LayoutInflater) context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                mOverlay = (RelativeLayout) inflater
                        .inflate(R.layout.phasechange, null);

                mWindowManager = (WindowManager) context
                        .getSystemService(Context.WINDOW_SERVICE);
                mWindowManager.addView(mOverlay, params);
                Button b = (Button) mOverlay.findViewById(R.id.button1);
                b.setOnClickListener(new OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        // TODO Auto-generated method stub
                        mWindowManager.removeView(mOverlay);
                    }
                });

            }

OTHER TIPS

Use window type TYPE_PHONE in place of TYPE_SYSTEM_OVERLAY, along with flag FLAG_NOT_FOCUSABLE.

Making view from the Code is always hectic and little bit tough to manage. so alternatively can u add the button in the Layout and make it visible and invisible according to your swipes.

and use below code to get the gestures

public class MyGestureDetector implements OnGestureListener {
        @Override
        public boolean onDown(MotionEvent arg0) {
            return false;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float arg3) {
            return setCurrentSwipeTab(e1, e2, velocityX, arg3);
        }

        @Override
        public void onLongPress(MotionEvent arg0) {
        }

        @Override
        public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
                float arg3) {
            return false;
        }

        @Override
        public void onShowPress(MotionEvent e) {
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return false;
        }
    }


public boolean setCurrentSwipeTab(MotionEvent e1, MotionEvent e2,
            float velocityX, float arg3) {
        try {
            if (Math.abs(e1.getY() - e2.getY()) > Util.SWIPE_MAX_OFF_PATH)
                return false;
            // Left to right swipe of the user detected
            if (e1.getX() - e2.getX() > Util.SWIPE_MIN_DISTANCE
                    && Math.abs(velocityX) > Util.SWIPE_THRESHOLD_VELOCITY) {

                }
                    // Nothing to do since you are at the Last tab!! it's task
                    // of the left swipe now
                }
            } else if (e2.getX() - e1.getX() > Util.SWIPE_MIN_DISTANCE
                    && Math.abs(velocityX) > Util.SWIPE_THRESHOLD_VELOCITY) {

        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

Your approach to this task is very unusual. Simply adding a new view would handle the task fine.

Add this code:

RelativeLayout layout = new RelativeLayout(this);
Button b = new Button(this);
b.setBackgroundColor(Color.LTGRAY);
b.setText("Click to Go");
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
b.setLayoutParams(params);
layout.addView(b);

//get a reference to your main layout:
ViewGroup myLayout = findViewById(R.id.whateverMayLayoutIdIs);
layout.addView(layout);

To hide the view, you can just remove it from the layout, or change its visibility.

The approach you were working on is very tricky, and others have had issues with handling touches. Examples include Android : Multi touch and TYPE_SYSTEM_OVERLAY and GestureDetector within a TYPE_SYSTEM_OVERLAY. Try this google search for more.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top