Android hardware menu button not working with Cordova 5.1.1 and Ionic 1.1.0

Android hardware menu button event 'menubutton' does not seem to be firing on document.
I have tried adding event listeners in a .run() block as most people recommend and also in a .controller() but to no avail.

.controller(function($document, $ionicSideMenuDelegate){

  var menuButtonFn = function(){
    console.log('in controller');
    $ionicSideMenuDelegate.toggleLeft();
  };

  $document.on('menubutton', menuButtonFn);
  document.addEventListener("menubutton", menuButtonFn, false);
})

.run(function($rootScope, $ionicPlatform, $cordovaStatusbar) {

  $ionicPlatform.ready(function() {

    function menuButtonFn(){
      console.log('here now');
      $rootScope.$broadcast('menubutton');
    }

    if (window.cordova) {
      document.addEventListener("menubutton", menuButtonFn, false);
    }
})

I have been testing on a Samsung Galaxy S4 using `ionic run android``. I don’t see any errors or logs in the chrome://inspect view and any other code is definitely not being triggered.
Not sure if I am missing something obvious. Has anyone else had the same problem?

Seems to have done the trick for me.

1 Like

Thanks! I had seen that before but didn’t realise that I could actually edit the Cordova platform code. A quick file search in the platforms directory proved otherwise. It still seems wrong to be changing cordova’s java code, but I guess that’s why it’s called a monkey patch.

I edited the method onDispatchKeyEvent in file platforms/android/CordovaLib/src/org/apache/cordova/CordovaWebViewImpl.java on line 549 and commented out the boundKeyCodes check as per below.


        @Override
        public Boolean onDispatchKeyEvent(KeyEvent event) {
            int keyCode = event.getKeyCode();
            boolean isBackButton = keyCode == KeyEvent.KEYCODE_BACK;
            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                if (isBackButton && mCustomView != null) {
                    return true;
                } else if (boundKeyCodes.contains(keyCode)) {
                    return true;
                } else if (isBackButton) {
                    return engine.canGoBack();
                }
            } else if (event.getAction() == KeyEvent.ACTION_UP) {
                if (isBackButton && mCustomView != null) {
                    hideCustomView();
                    return true;
                } else { //if (boundKeyCodes.contains(keyCode)) {
                    String eventName = null;
                    switch (keyCode) {
                        case KeyEvent.KEYCODE_VOLUME_DOWN:
                            eventName = "volumedownbutton";
                            break;
                        case KeyEvent.KEYCODE_VOLUME_UP:
                            eventName = "volumeupbutton";
                            break;
                        case KeyEvent.KEYCODE_SEARCH:
                            eventName = "searchbutton";
                            break;
                        case KeyEvent.KEYCODE_MENU:
                            eventName = "menubutton";
                            break;
                        case KeyEvent.KEYCODE_BACK:
                            eventName = "backbutton";
                            break;
                    }
                    if (eventName != null) {
                        sendJavascriptEvent(eventName);
                        return true;
                    }
                } 
                // else if (isBackButton) {
                //     return engine.goBack();
                // }
            }
            return null;
        }

Also here’s the Cordova issue opened about this for reference: https://issues.apache.org/jira/browse/CB-8921

Interesting. I made my change earlier in the file by adding one line to setButtonPlumbedToJs(), which adds support to boundKeyCodes that is later checked in onDispatchKeyEvent() :

@Override
public void setButtonPlumbedToJs(int keyCode, boolean override) {
    switch (keyCode) {
        case KeyEvent.KEYCODE_VOLUME_DOWN:
        case KeyEvent.KEYCODE_VOLUME_UP:
        case KeyEvent.KEYCODE_BACK:
        case KeyEvent.KEYCODE_MENU: // add menu button support
            // TODO: Why are search and menu buttons handled separately?
            if (override) {
                boundKeyCodes.add(keyCode);
            } else {
                boundKeyCodes.remove(keyCode);
            }
            return;
        default:
            throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
    }
}

Either way, I agree, editing core Cordova files seems dirty. Hopefully they’ll get it patched soon.