I want to make a module that could determine pressing the volume buttons Android devices. Although I do not know java, but I found the code that I need on the stackoverflow:

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    int action = event.getAction();
    int keyCode = event.getKeyCode();
    switch (keyCode) {
        case KeyEvent.KEYCODE_VOLUME_UP:
            if (action == KeyEvent.ACTION_DOWN) {
                //TODO
            }
            return true;
        case KeyEvent.KEYCODE_VOLUME_DOWN:
            if (action == KeyEvent.ACTION_DOWN) {
                //TODO
            }
            return true;
        default:
            return super.dispatchKeyEvent(event);
    }
}

Then I created an application in android studio that works successfully on my device and determines the volume buttons. Java code from the application:

package com.test.exampleapp;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.KeyEvent;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    TextView myTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        myTextView = (TextView)findViewById(R.id.myTextView);
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        int action = event.getAction();
        int keyCode = event.getKeyCode();
        switch (keyCode) {
            case KeyEvent.KEYCODE_VOLUME_UP:
                if (action == KeyEvent.ACTION_DOWN) {
                    myTextView.setText("Volume up pressed!");
                }
                return true;
            case KeyEvent.KEYCODE_VOLUME_DOWN:
                if (action == KeyEvent.ACTION_DOWN) {
                    myTextView.setText("Volume down pressed!");
                }
                return true;
            default:
                return super.dispatchKeyEvent(event);
        }
    }
}

Then I tried to convert this code into code for the module:

package org.godotengine.godot;

import android.app.Activity;
import android.util.Log;
import android.view.KeyEvent;

public class GodotVolumeButtons extends Godot.SingletonBase {
	
	private Activity activity = null; // The main activity of the game
	private int instance_id = 0;
	
	public void set_id(int instance_id)
	{
		this.instance_id = instance_id;
		Log.d("godot", "GodotVolumeButtons: set_id");
	}
	
	// @Override
	public boolean dispatchKeyEvent(KeyEvent event) {
		int action = event.getAction();
		int keyCode = event.getKeyCode();
		switch (keyCode) {
			case KeyEvent.KEYCODE_VOLUME_UP:
				if (action == KeyEvent.ACTION_DOWN) {
					Log.d("godot", "Volume down pressed!");
					GodotLib.calldeferred(instance_id, "_on_volume_up_pressed", new Object[] { });
				}
				return true;
			case KeyEvent.KEYCODE_VOLUME_DOWN:
				if (action == KeyEvent.ACTION_DOWN) {
					Log.d("godot", "Volume down pressed!");
					GodotLib.calldeferred(instance_id, "_on_volume_down_pressed", new Object[] { });
				}
				return true;
			default:
				return dispatchKeyEvent(event);
		}
	}
	
	/* Definitions
	 * ********************************************************************** */

	/**
	 * Initilization Singleton
	 * @param Activity The main activity
	 */
 	static public Godot.SingletonBase initialize(Activity activity) {
 		return new GodotVolumeButtons(activity);
 	}

	/**
	 * Constructor
	 * @param Activity Main activity
	 */
	public GodotVolumeButtons(Activity activity) {
		registerClass("GodotVolumeButtons", new String[] { "set_id" });
		this.activity = activity;
	}
}

With this code, export templates are compiled without errors. When debugging, this module is defined, but the calldeferred does not work. Please tell me, what did I do wrong, or what did not I do?

Does the Log.d("godot", "Volume down pressed!"); and Log.d("godot", "Volume down pressed!"); work? Which Godot version are you using?

Godot version is 2.1.4 logcat does not print Log.d("godot", "Volume down pressed!");and Log.d("godot", "Volume down pressed!"); but it prints:

! I/ViewRootImpl(25617): WindowInputEventReceiver onInputEvent!! KeyCode is 25, action is 0 ! I/View (25617): Key down dispatch to org.godotengine.godot.GodotView{839275d VFE..... .F...... 0,0-720,1280}, event = KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_VOLUME_DOWN, scanCode=0, metaState=0, flags=0xc0000008, repeatCount=0, eventTime=363203456, downTime=363203456, deviceId=-1, source=0x101 } ! ! I/ViewRootImpl(25617): WindowInputEventReceiver onInputEvent!! KeyCode is 25, action is 1 ! I/View (25617): Key up dispatch to org.godotengine.godot.GodotView{839275d VFE..... .F...... 0,0-720,1280}, event = KeyEvent { action=ACTION_UP, keyCode=KEYCODE_VOLUME_DOWN, scanCode=0, metaState=0, flags=0xc0000008, repeatCount=0, eventTime=363203456, downTime=363203456, deviceId=-1, source=0x101 }

It turns out that the dispatchKeyEvent function does not work. I looked at the admob module(https://github.com/kloder-games/godot-admob) and there is a calldeferred. There used thread:

activity.runOnUiThread(new Runnable()
		{
			@Override public void run()
			{ 
				...

And the threads use the ...Listener. For example, one of the threads uses the setRewardedVideoAdListener:

/* Rewarded Video
 * ********************************************************************** */
private void initRewardedVideo()
{
	activity.runOnUiThread(new Runnable()
	{
		@Override public void run()
		{
			MobileAds.initialize(activity);
			rewardedVideoAd = MobileAds.getRewardedVideoAdInstance(activity);
			rewardedVideoAd.setRewardedVideoAdListener(new RewardedVideoAdListener()
			{
				@Override
				public void onRewardedVideoAdLeftApplication() {
					Log.w("godot", "AdMob: onRewardedVideoAdLeftApplication");
					GodotLib.calldeferred(instance_id, "_on_rewarded_video_ad_left_application", new Object[] { });
				}
    					...

Do I understand correctly that for my module I need some kind of Listener?

5 years later