Search code examples
androidunity-game-enginelockscreenwakelock

Unity3D Android Lockscreen not shown when screen times out. (Wakelock?)


I am building an android app using Unity and it is coming along very well. However, I'm having an odd issue relating to the screen timing out and the lockscreen not showing.

What Should Happen

  • User stops playing
  • Screen Times out and turns off
  • Later, player returns and turns their phone back on
  • Lockscreen shows, user can enter their password, or otherwise unlock their phone
  • App regains focus and continues

What IS happening

  • User stops playing
  • Screen Times out and turns off
  • Later, player returns and turns their phone back on
  • Lockscreen does NOT show! The app is right in focus, bypassing the lockscreen all together
  • Users get mad that their security is compromised :(

Notes

  • This happens regardless of whether or not I'm using Android Plugins
  • I'm using Unity 4.2.0f4 (Though the changelogs for the more recent versions have nothing about this issue)
  • It even happens on a blank Android project
  • I've tested this on 5 different devices, all have the same problem

I suspect that this is caused by a wakelock that Unity does not give up when the screen times out. This causes the app to hold focus and the lockscreen never gets to 'load'. This is a pretty serious problem.

Does anyone know of any way to fix this?

Note: I've already asked this question on Unity Answers a little over a week ago and haven't gotten any responses yet. I thought maybe I'd have better luck here.


Solution

  • First I'd like to say thanks to MichaelTaylor3D's Answer for pointing me in the right direction.

    There were a few issues with the way he solved the problem that I think I have corrected:

    The first issue is with the KeyguardManager approach to locking the screen. This was depreciated in API version 8 and won't work on API 9+. The new solution uses the Device Admin API which seems very intrusive for a game.

    I looked through the UnityPlayer definition in eclipse and found a function called setWakeLock(boolean), however it is private.

    I made a custom android Activity. In it, I access a protected UnityPlayer function setWakeLock(boolean) and calls it in the onPause function.

    I admit this is less than ideal, but it does seem to work with no side effects. I've submitted a bug report to Unity, so hopefully this work around will not be required for long.

    public class UnityPlayerWithLockscreen extends UnityPlayerNativeActivity {
    
    
        @Override
        public void onCreate(Bundle savedInstanceState) 
        {
             super.onCreate(savedInstanceState);
        }
    
        //Provides access to the private UnityPlayer.setWakeLock(boolean) method.
        public void setWakeLock(boolean useWakelock) {
            Method setWakeLockMethod;
    
            //Use Reflection to get the setWakeLock(boolean) method from the UnityPlayer class
            setWakeLockMethod = mUnityPlayer.getClass().getDeclaredMethod("setWakeLock");
    
            //Set the method to me accessible
            setWakeLockMethod.setAccessible(true);
    
            //Invoke the method with our argument
            setWakeLockMethod.invoke(mUnityPlayer, useWakelock);
        }
    
    
        @Override
        protected void onPause()
        {
            super.onPause();
    
            //Force unity to release the wakelock
            setWakeLock(false);     
        }
    }
    

    Then you need to set this activity as the main activity in the AndroidManifest file:

    <?xml version="1.0" encoding="utf-8"?>
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".UnityPlayerWithLockscreen"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
    

    This solution also doesn't require any C# scripts or C# <-> Java interop.

    Again, I know this is sort of a hacky solution, but it seems to work on several devices regardless of API level with no side effects. Hopefully this gets fixed by Unity soon and will no longer require an ugly fix.