Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

menubutton not working anymore after upgrade to cordova 5+cordova android 4.0.0

I've recently upgraded to cordova 5 and removed/recreated android platform in version 4.0.0 and uninstalled/reinstalled all plugins.

I also had to upgrade android sdk to sdk 22 instead of 21.

Since the update, I'm no more able to catch the menubutton event as described in the cordova documentation.

As it's still referenced in the edge docs, I assume it should still be working and I've seen nothing about this in the release notes.

back button is still working.

I tried to set the target-sdk to 19, it did not solve anything about the issue.

Edit: I've dug into cordova source code and found in CordovaWebViewImpl.java I found a suspicious TODO comment :

   public void setButtonPlumbedToJs(int keyCode, boolean override) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_VOLUME_DOWN:
            case KeyEvent.KEYCODE_VOLUME_UP:
            case KeyEvent.KEYCODE_BACK:
                // 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);
        }
    }

Well my answer would be "IT SHOULDN'T!!!!"

Cordova makes a list of keycode to handle but does not add the menu button and later on the keycode is compared to KeyEvent.KEYCODE_MENU only after the keycode has been skipped because it's not in the list.

I've tried to add a case for the menu button, but it turns out the function is only called with the code of the back button.

So now I know why it doesn't work but still not how to fix it.

Edit 02/2016: As per latest Jira, the support of the menubutton is now fixed in java part in Cordova Android 5.1.0 but still not initialized from the javascript. For the moment, as indicated by Jira user Keith Wong, you need to add a javascript call before you add your event listener :

document.addEventListener("deviceready", function() {
    ...
    navigator.app.overrideButton("menubutton", true);  // <-- Add this line
    document.addEventListener("menubutton", yourCallbackFunction, false);
    ...
}, false);
like image 263
QuickFix Avatar asked May 18 '15 17:05

QuickFix


1 Answers

clarent's answer didn't do it for me, the menu button still didn't respond.

I tried several patches, one other suggestion to disable the boundKeyCodes check completely didn't do it either, because then the backbutton behaviour would be compromised.

The clean way to get the old behaviour back should be as follows. The boundKeyCodes check ensures, that custom behaviour is only executed when there actually is a custom event handler bound to the event. But binding an event handler to "menubutton" in your app's JS code no longer triggers the menubutton key code to be added to the boundKeyCodes list. This is because the setButtonPlumbedToJs method is never executed for the "menubutton" handler in the first place AND even if it would, the switch statement in this method doesn't handle KEYCODE_MENU.

You can get that behaviour back quite easily, first you will have to apply the change suggested by clarent:

  1. Handle KEYCODE_MENU

in CordovaLib/src/org/apache/cordova/CoreAndroid.java (around line 357, setButtonPlumbedToJs) add a case statement after the KEYCODE_BACK entry like this:

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:
    // 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);
  }
}

Then ensure that setButtonPlumbedToJs actually gets executed. You need two more changes for that.

  1. Add framework handler

In CordovaLib/src/org/apache/cordova/CoreAndroid.java (around line 243, overrideButton) make the method look like this (add the last else-if clause):

public void overrideButton(String button, boolean override) {

  if (button.equals("volumeup")) {
    webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
  }
  else if (button.equals("volumedown")) {
    webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
  }
  else if (button.equals("menubutton")) {
    webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_MENU, override);
  }
}
  1. Add javascript handler call

In platform_www/cordova.js (around line 1532, bootstrap) change this line:

cordova.addDocumentEventHandler('menubutton');

to this:

var menuButtonChannel = cordova.addDocumentEventHandler('menubutton');
menuButtonChannel.onHasSubscribersChange = function() {
  exec(null, null, APP_PLUGIN_NAME, "overrideButton", ['menubutton', this.numHandlers == 1]);
};

This will trigger the frameworks overrideButton method as soon as an event handler is added to "menubutton".

That should do it. I also added this solution as a comment to https://issues.apache.org/jira/browse/CB-8921 and might be filing a pull request shortly.

like image 103
FewKinG Avatar answered Oct 27 '22 19:10

FewKinG