Android and FLAG_SHOW_WHEN_LOCKED

Hi,

while I have my application running, there is a use-case where the application should be launched by another application while the keyguard is still on.

With other native applications, this works well, by using the following code in onCreate()

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);

I created a launcher activity that extends from CoronaActivity and sets those flags in the onCreate() method.

But with Corona Enterprise, it seems that there is an issue with the OpenGL. The Lua part launches fine, up until the part where the OpenGL loop needs to be entered. All that is shown on screen is an empty activity.

When the key guard is already disposed, everything works fine. But when turning off and turning back on the screen, the window tries to continue but again the screen remains dark.

For me it seems that this may be related to this StackOverview article, i.e. to the Z-order of the OpenGL surface control in Android.

Any hint on how I could get this working? It is really important to my application, that as long as the user launched it before keyguard turns on, or if launched by another service in the background, that the application is shown in front of the keyguard. This is part of some sort of “kiosk-mode”, where the owner of the tablets doesn’t want the user of the application to be able to access other settings and applications of the device.

Android’s multi-threaded “SurfaceView” derived objects such as the “GLSurfaceView” and “VideoView” are notoriously buggy when it comes to rendering in the correct z-order on the screen.  This is because they’re *not* actually rendered in your activities view hierarchy and rendered behind the activity, on a separate thread, and the Android OS compositor tries its best to then render it on top with the correct z-order, which it sometimes gets wrong.  The Class Overview in the link below describes how it works…
   http://developer.android.com/reference/android/view/SurfaceView.html
 
If your app doesn’t use any native Android UI such as text fields or webview, then you *might* be able to solve this problem by calling the GLSurfaceView.setZOrderOnTop() method and setting it to “true”.  This will force the OpenGL view to always be rendered on top.
   http://developer.android.com/reference/android/view/SurfaceView.html#setZOrderOnTop(boolean
 
You can’t fetch Corona’s GLSurfaceView directory.  But you can fetch it by traversing all of the activity’s child view, of which there should only be a few.  In your onCreate() method, you can do the above *after* calling super.onCreate(), which is where Corona will create its child views and its GLSurfaceView.  It should look something like the following (I coded this blind without compiling it)…

protected void onCreate(android.os.Bundle bundle) { // Let Corona create its view first. super.onCreate(bundle); // Now, hunt down the GLSurfaceView in the activity's child view hierarchy and reconfigure it. onInitGLSurfaceView(getWindow().getDecorView().getRootView()); } private void onInitGLSurfaceView(android.view.View view) { if (view instanceof android.opengl.GLSurfaceView) { android.opengl.GLSurfaceView glSurfaceView = (android.opengl.GLSurfaceView)view; glSurfaceView.setZOrderOnTop(true); } else if (view instanceof android.view.ViewGroup) { android.view.ViewGroup viewGroup = (android.view.ViewGroup)view; for (int index = viewGroup.getChildCount() - 1; index \>= 0; index--) { onInitGLSurfaceView(viewGroup.getChildAt(index)); } } }

Hi,

thanks, this is very similar to the approach I already tried (I used reflection to get a reference to the GLSurfaceView). I got it working with a Corona Cards project, but it seems that with Corona Enterprise, the Window gets created before I have the possibility to call setZOrderOnTop(true). Unfortunately, according to the JavaDoc and to my experience, the OnTop must be set before the parent Window is created. It seems that the Window is created in CoronaActivity.onCreate(), if I am not mistaken.

A potential workaround, which would require work on side of Corona, would be that the CoronaActivity would have a protected method protected bool isZOrderOnTop() { return false; } which it would check when creating the GLView, and which I could overwrite. Any way to get something like that added?

Or are there ways I could provide my own activity, that does NOT inherit from CoronaActivity and could still startup the Lua part?

Best regarsd,
Martin

I think calling the setZOrderOnTop() method in the onCreate() method should be fine.  Perhaps the issue is that your Corona project is not running at all?  Try putting a print() statement within your main.lua and verify that your project is getting started.  You can see the printed/logged output via the Android SDK’s “adb logcat” command line tool.

If it’s not starting up, then it might mean that your CoronaActivity derived class’ virtual method might be forgetting to call the super class’ method.  For example…

protected void onStart() { // Make sure to call the CoronaActivity's virtual method. super.onStart(); // Now do your stuff... }

Also, the one limitation with running your own derived CoronaActivity class is that Corona’s local/push notification system won’t work right.  When tapping on a notification in the status bar, Corona attempts to launch a CoronaActivity via an Android intent and isn’t aware of your derived class.  That’s the only limitation that I can think of.

Hi,

thanks for your response again. The application itself runs fine when being executed in unlocked mode, but won’t show anything while over the lock-screen. Super-class methods are called first-thing in onStart(), so this should not be the issue.

Best regards,

Martin

Okay.  Well this tell me that the GLSurfaceView *is* actually rendering because the Corona runtime state gets update just before every render pass.  This is an issue with the Android OS’ compositor failing to render the GLSurfaceView on top of the activity.

You can try calling the GLSurfaceView’s setZOrderMediaOverlay() method and setting it to true as well.

   http://developer.android.com/reference/android/view/SurfaceView.html#setZOrderMediaOverlay(boolean

Other than that, I’m not sure how else I can help.

Yes, I also suppose it got something to do with the Z-order only. The interesting part is, that I got it working using CoronaCards (with the sample application), so it should work. I suppose simply, that I am to late to the party when calling the setZOrderOnTo(), because it must be called before the Window is attached to the Window Manager according to JavaDoc.

I will keep playing around, thanks for the help and the info that I am not on the totally wrong path here :slight_smile:

Best regards,
Martin

What if you remove the GLSurfaceView from the ViewGroup and then re-add it?

Perhaps that might work.

Android’s multi-threaded “SurfaceView” derived objects such as the “GLSurfaceView” and “VideoView” are notoriously buggy when it comes to rendering in the correct z-order on the screen.  This is because they’re *not* actually rendered in your activities view hierarchy and rendered behind the activity, on a separate thread, and the Android OS compositor tries its best to then render it on top with the correct z-order, which it sometimes gets wrong.  The Class Overview in the link below describes how it works…
   http://developer.android.com/reference/android/view/SurfaceView.html
 
If your app doesn’t use any native Android UI such as text fields or webview, then you *might* be able to solve this problem by calling the GLSurfaceView.setZOrderOnTop() method and setting it to “true”.  This will force the OpenGL view to always be rendered on top.
   http://developer.android.com/reference/android/view/SurfaceView.html#setZOrderOnTop(boolean
 
You can’t fetch Corona’s GLSurfaceView directory.  But you can fetch it by traversing all of the activity’s child view, of which there should only be a few.  In your onCreate() method, you can do the above *after* calling super.onCreate(), which is where Corona will create its child views and its GLSurfaceView.  It should look something like the following (I coded this blind without compiling it)…

protected void onCreate(android.os.Bundle bundle) { // Let Corona create its view first. super.onCreate(bundle); // Now, hunt down the GLSurfaceView in the activity's child view hierarchy and reconfigure it. onInitGLSurfaceView(getWindow().getDecorView().getRootView()); } private void onInitGLSurfaceView(android.view.View view) { if (view instanceof android.opengl.GLSurfaceView) { android.opengl.GLSurfaceView glSurfaceView = (android.opengl.GLSurfaceView)view; glSurfaceView.setZOrderOnTop(true); } else if (view instanceof android.view.ViewGroup) { android.view.ViewGroup viewGroup = (android.view.ViewGroup)view; for (int index = viewGroup.getChildCount() - 1; index \>= 0; index--) { onInitGLSurfaceView(viewGroup.getChildAt(index)); } } }

Hi,

thanks, this is very similar to the approach I already tried (I used reflection to get a reference to the GLSurfaceView). I got it working with a Corona Cards project, but it seems that with Corona Enterprise, the Window gets created before I have the possibility to call setZOrderOnTop(true). Unfortunately, according to the JavaDoc and to my experience, the OnTop must be set before the parent Window is created. It seems that the Window is created in CoronaActivity.onCreate(), if I am not mistaken.

A potential workaround, which would require work on side of Corona, would be that the CoronaActivity would have a protected method protected bool isZOrderOnTop() { return false; } which it would check when creating the GLView, and which I could overwrite. Any way to get something like that added?

Or are there ways I could provide my own activity, that does NOT inherit from CoronaActivity and could still startup the Lua part?

Best regarsd,
Martin

I think calling the setZOrderOnTop() method in the onCreate() method should be fine.  Perhaps the issue is that your Corona project is not running at all?  Try putting a print() statement within your main.lua and verify that your project is getting started.  You can see the printed/logged output via the Android SDK’s “adb logcat” command line tool.

If it’s not starting up, then it might mean that your CoronaActivity derived class’ virtual method might be forgetting to call the super class’ method.  For example…

protected void onStart() { // Make sure to call the CoronaActivity's virtual method. super.onStart(); // Now do your stuff... }

Also, the one limitation with running your own derived CoronaActivity class is that Corona’s local/push notification system won’t work right.  When tapping on a notification in the status bar, Corona attempts to launch a CoronaActivity via an Android intent and isn’t aware of your derived class.  That’s the only limitation that I can think of.

Hi,

thanks for your response again. The application itself runs fine when being executed in unlocked mode, but won’t show anything while over the lock-screen. Super-class methods are called first-thing in onStart(), so this should not be the issue.

Best regards,

Martin

Okay.  Well this tell me that the GLSurfaceView *is* actually rendering because the Corona runtime state gets update just before every render pass.  This is an issue with the Android OS’ compositor failing to render the GLSurfaceView on top of the activity.

You can try calling the GLSurfaceView’s setZOrderMediaOverlay() method and setting it to true as well.

   http://developer.android.com/reference/android/view/SurfaceView.html#setZOrderMediaOverlay(boolean

Other than that, I’m not sure how else I can help.

Yes, I also suppose it got something to do with the Z-order only. The interesting part is, that I got it working using CoronaCards (with the sample application), so it should work. I suppose simply, that I am to late to the party when calling the setZOrderOnTo(), because it must be called before the Window is attached to the Window Manager according to JavaDoc.

I will keep playing around, thanks for the help and the info that I am not on the totally wrong path here :slight_smile:

Best regards,
Martin

What if you remove the GLSurfaceView from the ViewGroup and then re-add it?

Perhaps that might work.