14

How can i do that?

Current solution

I launch a transparent activity, that catches the back press, forwards it to my service and closes itself afterwards. But this activity will be visible in the current running activities and therefore it's not a very beautiful solution.

Solutions seen

I've seen an app that does catch the back press in a service - without an activity that catches the back press. If I show the current running activities, there is nothing from this app.

Question

How can this be done? I've read so many threads that say, this is not possible, but I can see, that there are apps that achieve that somehow...

prom85
  • 16,896
  • 17
  • 122
  • 242

4 Answers4

12

I think I found out how it works... DON'T USE WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE in your overlays views + overwrite the dispatchKeyEvent of your view:

 @Override
public boolean dispatchKeyEvent(KeyEvent event)
{
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK)
    {
        // handle back press
        // if (event.getAction() == KeyEvent.ACTION_DOWN)
        return true;
    }
    return super.dispatchKeyEvent(event);
}
prom85
  • 16,896
  • 17
  • 122
  • 242
  • How to do this in a service class – Ankesh kumar Jaisansaria Aug 19 '16 at 10:49
  • 5
    Service class don't override such method – Ankesh kumar Jaisansaria Aug 19 '16 at 10:49
  • What flag to use instead of `FLAG_NOT_FOCUSABLE`? – Sigmund Nov 30 '16 at 07:21
  • 1
    Depends on what you want... I use `WindowManager.LayoutParams.TYPE_SYSTEM_ERROR` for my overlays type and `WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH` for the flags... This is working good for a sidebar like app... – prom85 Nov 30 '16 at 07:35
  • 1
    @prom85 You should not use TYPE_SYSTEM_ERROR as that can be misinterpreted as malware. https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_NOT_TOUCH_MODAL is typically the best choice, because it allows focus on the view, but does not prevent outside touch events, while FLAG_WATCH_OUTSIDE_TOUCH requires you to specify what outside touches are passed. – Abandoned Cart Apr 13 '17 at 21:29
  • I override dispatchKeyEvent but never get call back. I tried TYPE_SYSTEM_OVERLAY, TYPE_PHONE along with FLAG_NO_FOCUSABLE flags. – shantanu May 21 '17 at 19:55
  • @prom85 How to override dispatchKeyEvent when you are working with a view? – Abhiroj Panwar May 27 '17 at 18:57
6

I found solution for this issue,It's working good.

public class MyFooterService extends Service{
View myview;
WindowManager wm;
FrameLayout wrapper;
public MyFooterService() {

}
 @Override
public void onCreate() {
    Log.d(TAG, "onCreate called");
    LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
    wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            90,  //height of ur layout
            WindowManager.LayoutParams.TYPE_PHONE,
            0,
            PixelFormat.TRANSLUCENT);

    params.gravity = Gravity.BOTTOM ;
    params.x = 0;
    params.y = 0;
   wrapper = new FrameLayout(this) {
        @Override
        public boolean dispatchKeyEvent(KeyEvent event) {
            if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) {
              // handle the back button code;
             return true;
            }
          return super.dispatchKeyEvent(event);
        }
       //if pressed home key,
      public void onCloseSystemDialogs(String reason) {
            //The Code Want to Perform.
            System.out.println("System dialog " + reason);
            if (reason.equals("homekey")) {
                // handle home button 
            }
        }

     };
   myview = li.inflate(R.layout.my_footer, wrapper);   // here set into your own layout
   wm.addView(myview, params);

}
}
5

If you have an overlay window attached in a WindowManager in your service, put your view the attribute setFocusableInTouchMode(true), and put a key listener. You'll receive key events, like in this example:

view.setFocusableInTouchMode(true);
view.setOnKeyListener(new View.OnKeyListener() {
    @Override
    public boolean onKey(View v, int keyCode, KeyEvent event) {
        if(keyCode == KeyEvent.KEYCODE_BACK) {
            stopSelf();
            return true;
        }
        return false;
    }
});

Edited, I didn't use good stackoverflow account

0

You can catch the back button click event. For this you need to create container class of your OverlayView. For example: create class Overlay which will extends some ViewGroup class. Than, in the class, inflate your xml layout and add it to your Overlay.class ViewGroup. Than in Overlay.class override method dispatchKeyEvent(KeyEvent event). That's all!

class Overlay extends FrameLayout{
  
  public Overlay(@NonNull Context context) {
        super(new ContextThemeWrapper(context, R.style.AppTheme));

        initView();
    }
    
    private void initView() {
      //inflate your xml here
      //than do: this.addView(<inflated view>);
      //And in the end add your Overlay to WindowManager (in Service class of course).
    }
    
     @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
            //do staff here
            // and return True!
            return true;
        }
        return super.dispatchKeyEvent(event);
    }
}
void
  • 1