41

I am trying to detect when the physical Menu button on my Android phone has been pressed. I though the code below would work but it does not. Where am I going wrong please?

The error returned is 'Illegal modifier for parameter onKeyDown; only final is permitted'

public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_MENU) {
        // Do Stuff
    } else {
        return super.onKeyDown(keyCode, event);
    }
}
jdphenix
  • 15,022
  • 3
  • 41
  • 74
Entropy1024
  • 7,847
  • 9
  • 30
  • 32
  • 5
    It would be great if you can accept an answer, as this question is thoroughly answered by now. – Ken Jun 27 '12 at 01:51

6 Answers6

83

I'd look for an up key event, rather than a down event, with onKeyUp.

public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_MENU) {
        // ........
        return true;
    }
    return super.onKeyUp(keyCode, event);
}

We return true because we're handling the event; return false if you want the system to handle the event too.

You can do all of this in your Activity instance too because Activity is a known indirect subclass of KeyEvent.

Ken
  • 30,811
  • 34
  • 116
  • 155
  • Also have a look at the docs [KeyEvent.Callback](http://developer.android.com/reference/android/view/KeyEvent.Callback.html) and here is an [example](http://developer.android.com/training/keyboard-input/commands.html) – IT-Dan Nov 06 '13 at 06:37
  • Its a wrong answer it never works. Please see below the answer. – Ahmad Arslan Apr 15 '15 at 11:05
  • Worked for me like a charm. I was skeptical, because I tried at first onKeyDown(), and that event for the menu button never trickled down to my activity, was consumed somewhere in the "action" toolbar. – gregko May 29 '15 at 22:37
  • Doesn't work at least on Samsung S10+ with Android 10. – toto_tata Jun 05 '20 at 06:36
11

Based on all of the above this appears to be the correct implementation that will consume menu key "up" events only and pass on other key events to the superclass.

public boolean onKeyUp(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_MENU) {
        // ...
        return true;
    } else {
        return super.onKeyUp(keyCode, event);
    }
}
mbonness
  • 1,612
  • 1
  • 18
  • 20
5
public boolean onKeyDown(int keyCode, KeyEvent event) { 
    //Checking for the "menu" key
    if (keyCode == KeyEvent.KEYCODE_MENU) { 
        if (mDrawerLayout.isDrawerOpen(mDrawerList)) {
            mDrawerLayout.closeDrawers();
        } else {
            mDrawerLayout.openDrawer(Gravity.RIGHT);
        }
        return true;
    } else {
        return super.onKeyDown(keyCode, event);
    }
}
ihab alnaqib
  • 59
  • 1
  • 1
  • I was looking for this exact code :) Hiding and showing the left hand Navigation Drawer. Thanks. – Camille Sévigny Jan 29 '14 at 20:07
  • It seems to be the same detection method as the one in the question. The only difference is `return`ing `true` in the `if` block. If that's the only thing needed to solve the problem, it should be explicitly stated, and the irrelevant parts (the `mDrawerLayout` stuff) removed. Then this could be better than the current top solution, because this answer doesn't require changing `onKeyDown` to `onKeyUp`, just adding a `return true;` in the `if` block. Only if it works, of course... – Tamás Bolvári Sep 21 '18 at 23:44
1

Make sure you override the onKeyDown method in your Activity class. There is another onKeyDown method in the View class but it wont be called if the menu key is pressed.

Alexanus
  • 679
  • 4
  • 22
0

If you did handle the event just return true, if you didn't return false so the Android system can pass the event to the rest of the components to handle it.

Ameen
  • 1
-3

I have a very cool answer of this question I have tried it from the past 1 year and just found out the solution.

Please look at the answer below.

Create a class with the name of HomeWatcher. Exactly use the below code with the name of HomeWatcher.

public class HomeWatcher {
    static final String TAG = "HomeWatcher";
    private Context mContext;
    private IntentFilter mFilter;
    private OnHomePressedListener mListener;
    private InnerRecevier mRecevier;

    public interface OnHomePressedListener {
        public void onHomePressed();

        public void onHomeLongPressed();

        //public void onLockLongPressed();
    }

    public HomeWatcher(Context context) {
        mContext = context;
        mFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
    }


    public void setOnHomePressedListener(OnHomePressedListener listener) {
        mListener = listener;
        mRecevier = new InnerRecevier();
    }

    public void startWatch() {
        try{
        if (mRecevier != null) {
            mContext.registerReceiver(mRecevier, mFilter);
        }
        }catch(Exception e){}
    }


    public void stopWatch() {
        try{
        if (mRecevier != null) {
            mContext.unregisterReceiver(mRecevier);
        }
        }catch(Exception e){}
    }


    class InnerRecevier extends BroadcastReceiver {
        final String SYSTEM_DIALOG_REASON_KEY = "reason";
        final String SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS = "globalactions";
        final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
        final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
        //final String SYSTEM_DIALOG_REASON_Lock = "lock";

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (action.equals(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) {
                String reason = intent.getStringExtra(SYSTEM_DIALOG_REASON_KEY);

                if (reason != null) {
                    Log.e(TAG, "action:" + action + ",reason:" + reason);
                    if (mListener != null) {
                        if (reason.equals(SYSTEM_DIALOG_REASON_HOME_KEY)) {
                            mListener.onHomePressed();
                        } else if (reason
                                .equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
                            mListener.onHomeLongPressed();

                        }
                    /*  else if (reason
                                .equals(SYSTEM_DIALOG_REASON_Lock)) {
                            mListener.onLockLongPressed();

                        }*/

                    }
                }
            }
        }
    }
}

You need to declare the Homewatcher on your desired class where you wanted to detect the home button and Recent apps button.

public class MainActivity extends  Activity {

    private HomeWatcher mHomeWatcher;

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

         setContentView(R.layout.activity_main);
    try {

            mHomeWatcher = new HomeWatcher(this);
            mHomeWatcher.setOnHomePressedListener(new OnHomePressedListener() {
                @Override
                public void onHomePressed() {
                    Log.e(TAG, "onHomePressed");


                }
               @Override
                public void onHomeLongPressed() {
                    Log.e(TAG, "recent apps");

                }


            });
            mHomeWatcher.startWatch();
        } catch (Exception e) {
        }

    }

In the end of this you just need to add onPause and onResume Overide method like this.

@Override
    protected void onResume() {
        super.onResume();

        try {
            mHomeWatcher.startWatch();

        } catch (Exception e) {
        }
    }
    @Override
    protected void onPause() {
        super.onPause();

        try {
            mHomeWatcher.stopWatch();

        } catch (Exception e) {
        }
}

A very simple and beautiful answer. Waiting for the votes and accepted answer :p

Ahmad Arslan
  • 4,498
  • 8
  • 38
  • 59