Android black screen on resume fix (works with expansion files too)

Hello Cocos-2dx community =)

For the past two days I have been trying to resolve the issue of Android’s GL context being lost on app resume. Version 2.1.5 brought in a bug fix for this issue, which I’ve had success with on a few devices. However, the fix doesn’t take in to account textures loaded from an expansion file. I tried reloading textures manually on AppDelegate::applicationWillEnterForeground but I came across some unusual behaviour. Here’s what I discovered:

  • The EGL context can be lost AFTER applicationWillEnterForeground
  • Reloading textures in applicationWillEnterForeground does not guarantee textures will remain loaded until the next applicationDidEnterBackground event.
  • Textures should be reloaded in GLSurfaceView.Renderer.onSurfaceCreated

My current solution is to put an arbitrary delay after applicationWillEnterForeground before reloading textures. A long term fix would be to implement native callbacks for GLSurfaceView.Renderer.onSurfaceCreated and make CCTextureCache/VolatileTexture aware of expansion files.

Hope this helps!

A few links that helped me along the way:
http://www.cocos2d-x.org/news/82
http://www.cocos2d-x.org/boards/6/topics/27903
http://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer.html#onSurfaceCreated(javax.microedition.khronos.opengles.GL10, javax.microedition.khronos.egl.EGLConfig)

did you create an issue for this?

ps: we are not using expansion packs, and the black screen problem persists too

Hey Jesus,

Have you tried calling CCTextureCache::sharedTextureCache()->reloadAllTextures() ? You will need to define CC_ENABLE_CACHE_TEXTURE_DATA, see CCPlatformMacros.h

Mark

Hi Mark,

Where should I call that method? I guessed the problem was fixed by default on 2.1.5, it needs configuration every time?

Thanks.

AppDelegate::applicationWillEnterForeground

please try this (Cocos2dActivity.java) :

private void resumeGame() {
    mIsRunning = true;
    Cocos2dxHelper.onResume();
    this.mGLSurfaceView.onResume();
    Log.d(TAG, "RESUME COCOS2D");
}

private void pauseGame() {
    mIsRunning = false;
    Cocos2dxHelper.onPause();
    this.mGLSurfaceView.onPause();
    Log.d(TAG, "PAUSE COCOS2D");
}

private boolean mIsRunning = false;
private boolean mIsOnPause = false;

@Override
protected void onResume() {
    super.onResume();
    Log.d(TAG, "ACTIVITY ON RESUME");
    mIsOnPause = false;
}

@Override
protected void onPause() {
    super.onPause();
    Log.d(TAG, "ACTIVITY ON PAUSE");
    mIsOnPause = true;
    if (mIsRunning) {
        pauseGame();
    }
}

@Override
public void onWindowFocusChanged(final boolean hasWindowFocus) {
    super.onWindowFocusChanged(hasWindowFocus);
    Log.d(TAG, "ACTIVITY ON WINDOW FOCUS CHANGED " + (hasWindowFocus ? "true" : "false"));
    if (hasWindowFocus && !mIsOnPause) {
        resumeGame();
    }
}

@Mark Nguyen
I think you should listen the event named “EVNET_COME_TO_FOREGROUND”.
You can refer to CCDrawNode.cpp for the detail information of usage.

@YuLei Liao
Thanks for your snippet.
I’m using it in my project but it doesn’t cover all possible cases.

For example on some devices (Motorola Xoom [4.0.4] and HTC One [4.2.2] in my case) when clock alarm is opened above our main activity OS sends callbacks in the following order:

  • onPause()
  • onWindowFocusChanged(false)
  • onWindowFocusChanged(true)
  • onResume()

and we lose resumeGame() call. As the result applicationWillEnterForeground event isn’t worked and game is frozen.

Note that on some devices onWindowFocusChanged is called only when you select “shooze” on alarm.

I’ve tried use solution as described there (it’s very close to yours) some time ago but it doesn’t solve black screen problem. Still I’ve used it for sound.

— Nick

Hi, If anyone’s experiencing black texture with android (cocos2d-x 2.2.1) be sure that you reload any custom shader(s). Indeed if you write your own shader you’ll have to reload them in your main.cpp (e.g. proj.android/jni/hellocpp/main.cpp). If you’d like more info check my post here.
Regards, Laurent

This problem stills exists in cocos2d-x-3.0rc0, but the doc of reloadAllTextures() says “should not call it, called by frame work”.

Now what should we do?

@Timothy
Which device did you test on?

@zhangxm LG P990 with android 2.3.7

Only labels are shown after resuming the game.

Oh, i don’t have the device to test.
Will you try latest codes in github.
We use Java Activity to resolve black screen issue on some Android devices.
More information can refer to this thread.

hi all!
I use RenderTexture in my game, and it lost its context after resume in Android. The same bug is in Cocos_CppTests for “Node: RenderTexture” test.

Does anyone know how to fix this?
Thanks.