Android back button exits game

Hi All,
I’m trying to handle the Android back button click in my game. I used the EventListenerKeyboard to listen to the event and I added a log so I know my code is indeed executed, but this doesn’t stop the device from exiting my game and returning to the home screen after it executes my code.
How do I prevent the device from exiting my game?

I’m using cocos2d-x c++ 3.6 and the device I’m testing it on is a Galaxy S4 with Android 5.0.1.

Thanks

try to call setKeypadEnabled(true); from init function.

add in .h file
void onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event);

and in cpp file

void ClassName::onKeyReleased(EventKeyboard::KeyCode keyCode, Event* event) {
if (keyCode == EventKeyboard::KeyCode::KEY_ESCAPE)
{
CCLOG(“Back button clicked”);
}
}

This will prevent you to exit from game.

Hi @anjanjis,

I’m not using layers as I understand they are no longer needed and setKeypadEnabled is a layer function.
However, I did check what setKeypadEnabled does in cocos’ code and it just registers an EventListenerKeyboard just as I do so there doesn’t seem to be anything special there.
You can have a look here at line 294: https://github.com/cocos2d/cocos2d-x/blob/v3/cocos/2d/CCLayer.cpp

Do you have any other suggestions?

If your app doesn’t register as an keypad event listener, then Android handles any button presses how it deems, which in this case is to go “back” to the device’s home screen.

@hawkwood, I register to the event listener just as the layer does in setKeypadEnabled.
Further, I added a CCLOG call and my code is running in response to the back button click, but after my code runs the device still closes my game.

Is there anything else I need to do other than registering for the event?

// android back press event
auto touchListener = EventListenerKeyboard::create();
touchListener->onKeyReleased = [](cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event *event)
{
    if (keyCode == EventKeyboard::KeyCode::KEY_BACK)
    {
        Director::getInstance()->end();
    }
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);

Just add this to any node/layer/scene

3 Likes

@milos1290, As I understand this will exit my game when the back button is pressed, I’m trying NOT to exit my game when the back button is pressed.

Oh, sorry i thought you want to exit the game on back pressed.

This is strange issue, by default back button does nothing in cocos2d-x. You have to manually catch it and do what you want with it.

Make sure you didn’t override onBackPressed in your Activity.

No, I didn’t override the onBackPressed. Actually I tried overriding it to solver the problem, but that didn’t help.
Do I need to add some permissions or something to the android manifest to make it work?

Do you use a web view in your app? I once had an issue that once the web view loaded, it would start catching the BACK button presses, and thus exiting the app.

Hi @hawkwood,

I do have a webview. So how did you solve the issue in your app?

In cocos2d-x-3.5/cocos/platform/android/java/src/org/cocos2dx/lib/Cocos2dxWebView.java

added:

import android.view.KeyEvent;

and

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
	// Log.d("MyWebView","onKeyDown BLOCKED");
	return true;
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
	// Log.d("MyWebView","onKeyUp BLOCKED");
	return true;
}

before

@SuppressLint("SetJavaScriptEnabled")

Hi @hawkwood,
I’m sorry for the delay but I just got around to testing your suggestion but unfortunately it didn’t work…
Does anyone have any other suggestion for solving this problem?

OK, I’ve found the problem. I had several functions that responded to the back button at once instead of only one and one of them called director.end.

not working . always show unfortunatlly stopped.

For me it works perfectly well,
(works on android 5 and 6 atleast as far as I’ve tested)

    /*ANDROID: Back Button Press Event*/
    auto touchListener = EventListenerKeyboard::create();
    touchListener->onKeyReleased = [](cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event *event)
    {
        if (keyCode == EventKeyboard::KeyCode::KEY_BACK) {
             Director::getInstance()->end();
        }
    };
    _eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);

And if things are not working for you, then you’re expected to tell the details of the environment atleast. You’re a tech guy, you must understand that solution won’t appear out of thin air if you’re seeking help from others.

i have Try this but still not working tell me other setting for this …

when i pressed back button

==============================================================================

12-02 11:25:55.171: E/InputEventSender(18959): Exception dispatching finished signal.
12-02 11:25:55.171: E/MessageQueue-JNI(18959): Exception in MessageQueue callback: handleReceiveCallback
12-02 11:25:55.172: E/MessageQueue-JNI(18959): java.lang.NullPointerException: Attempt to invoke virtual method ‘boolean org.cocos2dx.lib.Cocos2dxVideoHelper$VideoHandler.sendEmptyMessage(int)’ on a null object reference
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at org.cocos2dx.lib.Cocos2dxGLSurfaceView.onKeyDown(Cocos2dxGLSurfaceView.java:315)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.KeyEvent.dispatch(KeyEvent.java:2654)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.View.dispatchKeyEvent(View.java:9237)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1640)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1640)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1640)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1640)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at com.android.internal.policy.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:2395)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at com.android.internal.policy.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1727)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.app.Activity.dispatchKeyEvent(Activity.java:2729)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at com.android.internal.policy.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2310)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4139)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4101)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3654)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3707)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3673)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3799)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3681)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3856)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3654)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3707)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3673)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3681)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3654)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3707)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3673)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3832)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:3993)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2261)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:1882)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:1873)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2238)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.os.MessageQueue.nativePollOnce(Native Method)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.os.MessageQueue.next(MessageQueue.java:323)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.os.Looper.loop(Looper.java:135)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at android.app.ActivityThread.main(ActivityThread.java:5443)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at java.lang.reflect.Method.invoke(Native Method)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
12-02 11:25:55.172: E/MessageQueue-JNI(18959): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
12-02 11:25:55.172: D/AndroidRuntime(18959): Shutting down VM
12-02 11:25:55.173: E/AndroidRuntime(18959): FATAL EXCEPTION: main
12-02 11:25:55.173: E/AndroidRuntime(18959): Process: com.imobigames.PrincessFashionSalon, PID: 18959
12-02 11:25:55.173: E/AndroidRuntime(18959): java.lang.NullPointerException: Attempt to invoke virtual method ‘boolean org.cocos2dx.lib.Cocos2dxVideoHelper$VideoHandler.sendEmptyMessage(int)’ on a null object reference
12-02 11:25:55.173: E/AndroidRuntime(18959): at org.cocos2dx.lib.Cocos2dxGLSurfaceView.onKeyDown(Cocos2dxGLSurfaceView.java:315)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.KeyEvent.dispatch(KeyEvent.java:2654)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.View.dispatchKeyEvent(View.java:9237)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1640)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1640)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1640)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewGroup.dispatchKeyEvent(ViewGroup.java:1640)
12-02 11:25:55.173: E/AndroidRuntime(18959): at com.android.internal.policy.PhoneWindow$DecorView.superDispatchKeyEvent(PhoneWindow.java:2395)
12-02 11:25:55.173: E/AndroidRuntime(18959): at com.android.internal.policy.PhoneWindow.superDispatchKeyEvent(PhoneWindow.java:1727)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.app.Activity.dispatchKeyEvent(Activity.java:2729)
12-02 11:25:55.173: E/AndroidRuntime(18959): at com.android.internal.policy.PhoneWindow$DecorView.dispatchKeyEvent(PhoneWindow.java:2310)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$ViewPostImeInputStage.processKeyEvent(ViewRootImpl.java:4139)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:4101)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3654)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3707)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3673)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3799)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3681)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3856)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3654)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3707)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3673)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3681)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3654)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3707)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3673)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3832)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.ViewRootImpl$ImeInputStage.onFinishedInputEvent(ViewRootImpl.java:3993)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.inputmethod.InputMethodManager$PendingEvent.run(InputMethodManager.java:2261)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.inputmethod.InputMethodManager.invokeFinishedInputEventCallback(InputMethodManager.java:1882)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.inputmethod.InputMethodManager.finishedInputEvent(InputMethodManager.java:1873)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.inputmethod.InputMethodManager$ImeInputEventSender.onInputEventFinished(InputMethodManager.java:2238)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.view.InputEventSender.dispatchInputEventFinished(InputEventSender.java:141)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.os.MessageQueue.nativePollOnce(Native Method)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.os.MessageQueue.next(MessageQueue.java:323)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.os.Looper.loop(Looper.java:135)
12-02 11:25:55.173: E/AndroidRuntime(18959): at android.app.ActivityThread.main(ActivityThread.java:5443)
12-02 11:25:55.173: E/AndroidRuntime(18959): at java.lang.reflect.Method.invoke(Native Method)
12-02 11:25:55.173: E/AndroidRuntime(18959): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:728)
12-02 11:25:55.173: E/AndroidRuntime(18959): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
12-02 11:25:57.749: I/Process(18959): Sending signal. PID: 18959 SIG: 9

I am using webview in my game. When the webview loads afresh, the back button does nothing when pressed (that’s fine, since there is nothing to go back to).

In the webview when I navigate to another page (by clicking a link), and then if I press back button, the game closes (I think it’s not a crash, since when I open the app again, it doesn’t run from the beginning, but a blank screen appears, where I cannot do anything).

I think there are two operations, happening here:

  1. It closes the webview.
  2. Back button exists the game (only if you have navigated inside the webview to more that 1 page).

Code setup:
I am NOT setting setKeyboardEnabled to true. Not altering the back button functionality.

Another case: I used setKeyboardEnabled (true) and then handling the back button as follows:
void HomeScreen::onKeyReleased(cocos2d::EventKeyboard::KeyCode keyCode, cocos2d::Event * event)
{
if (keyCode == cocos2d::EventKeyboard::KeyCode::KEY_BACK) {
auto appHomeLayer = this->getChildByName<Layer*>(“AppHomeLayer”);
if (appHomeLayer) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID || CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
if (_appHomeWebview && _appHomeWebview->canGoBack()) {
_appHomeWebview->goBack();
}
#endif
}
}
}

I debugged putting break point. onKeyReleased function is called, when webview is just loaded afresh, and it doesn’t do anything, since canGoBack() returns false.
When I navigate to other page and then press back button, onKeyReleased is never called. And the app closes is the same fashion as described above.

Version Cocos2d-x V3.10.

Let e know if you need any other info?
@udirub @slackmoehrle @SonarSystems @hawkwood @energyy , could you please help on this issue?

Any suggestions, anyone ?
@udirub @slackmoehrle @SonarSystems @hawkwood @energyy.