Search code examples
javaandroidandroid-permissionswear-osandroid-lifecycle

Wear OS Permissions screen never shows on first run of app - black screen instead


I'm using the following code from this answer to check and request permissions in my Wear OS app's onResume() method.

(I have tried various self-written code for the checks and requests and have had the same results with those, but this code seems like a neat little function to use that is easily expandable.)

public boolean checkAndRequestPermissions() {

    Log.d("checkAndRequestPermissions", "starting check");

    int internet = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE);
    int loc_coarse = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION);
    int loc_fine = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
    List<String> listPermissionsNeeded = new ArrayList<>();

    if (internet != PackageManager.PERMISSION_GRANTED) {
        Log.d("checkAndRequestPermissions", "INTERNET missing");
        listPermissionsNeeded.add(Manifest.permission.ACCESS_NETWORK_STATE);
    }
    if (loc_coarse != PackageManager.PERMISSION_GRANTED) {
        Log.d("checkAndRequestPermissions", "COARSE_LOCATION missing");
        listPermissionsNeeded.add(Manifest.permission.ACCESS_COARSE_LOCATION);
    }
    if (loc_fine != PackageManager.PERMISSION_GRANTED) {
        Log.d("checkAndRequestPermissions", "FINE_LOCATION missing");
        listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
    }

    if (!listPermissionsNeeded.isEmpty()) {
        Log.d("checkAndRequestPermissions", "Requesting missing permissions");
        ActivityCompat.requestPermissions((Activity) this, listPermissionsNeeded.toArray
                (new String[listPermissionsNeeded.size()]), 1);
        return false;
    }
    return true;
}

When my app is installed and run for the first time - either on the emulator or a real device - the app starts, runs through onCreate without problems, enters onResume and calls the above method. (I have added lots of debug output to both onCreate and onResume to see the progress and all is fine)

I can see the permission checks and can see that both COARSE_LOCATION and FINE_LOCATION are found to be missing as expected (ACCESS_NETWORK_STATE seems to be enabled by default).

I then see that the app is about to request permissions.

At this point my app enters onPause, presumably to display the permission request dialog, but then everything stops.

Nothing more in logcat and the device display goes black and remains black.

This is what the logcat shows in debug for my app:

D/onCreate: starting
D/NetworkSecurityConfig: No Network Security Config specified, using platform default
W/3words_for_wea: Accessing hidden method Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard; (light greylist, reflection)
W/3words_for_wea: Accessing hidden method Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V (light greylist, reflection)
    Accessing hidden method Ldalvik/system/CloseGuard;->warnIfOpen()V (light greylist, reflection)
D/onCreate: set up bindings and animations
D/onCreate: set up on click listeners
D/onCreate: end of onCreate
D/onResume: onResume - last w3wAddress = 
D/checkAndRequestPermissions: starting check
D/checkAndRequestPermissions: COARSE_LOCATION missing
    FINE_LOCATION missing
    Requesting missing permissions
D/OpenGLRenderer: HWUI GL Pipeline
D/onPause: onPause
D/: HostConnection::get() New Host Connection established 0xdbc22500, tid 4031
I/ConfigStore: android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasWideColorDisplay retrieved: 0
    android::hardware::configstore::V1_0::ISurfaceFlingerConfigs::hasHDRDisplay retrieved: 0
I/OpenGLRenderer: Initialized EGL, version 1.4
D/OpenGLRenderer: Swap behavior 1
W/OpenGLRenderer: Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...
D/OpenGLRenderer: Swap behavior 0
D/EGL_emulation: eglCreateContext: 0xdb09c3a0: maj 2 min 0 rcv 2
D/EGL_emulation: eglMakeCurrent: 0xdb09c3a0: ver 2 0 (tinfo 0xe7e56ab0)
D/EGL_emulation: eglMakeCurrent: 0xdb09c3a0: ver 2 0 (tinfo 0xe7e56ab0)

If I return to the device home screen and re-open the app the permissions request dialog opens up immediately and I can grant permissions and the app starts as expected.

Another oddity I observed, when the device is in this 'black screen but on' state, I am unable to restart the app from Android Studio. Android studio still thinks the app is running (I have the expected stop and restart buttons shown in the IDE toolbar for a running app), but clicking either the restart-with-stop or the restart-auto buttons does nothing.

However, if I switch the logcat view from debug to verbose, logcat empties. If I Return to the debug logcat it remains empty, so it is as though something has actually crashed, but there is no log of it for my app.

If I look at the system_process logcat, rather than my app, I see constantly repeated messages as below:

1874-1995/system_process I/GnssLocationProvider: WakeLock acquired by sendMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@97cf332)
1874-1898/system_process I/GnssLocationProvider: WakeLock released by handleMessage(REPORT_SV_STATUS, 0, com.android.server.location.GnssLocationProvider$SvStatusInfo@97cf332)

Note that nothing that requires the requested permissions is being run before the required permissions have been confirmed as granted.

What can be causing the black screen freeze, and how can I prevent it?


Solution

  • I have managed to resolve this by adopting a 'best practice approach' of requiring user interaction to prompt the permissions request - even though this doesn't really seem appropriate for an app whose primary/only purpose is showing your location!

    To acheieve this, my app no longer tries to request permissions from onCreate() or onResume and instead just shows a prominent button on screen if the permissions are not already granted. When the user clicks the button the permission check and request code above is run.

    To make this a bit easier, I modified the above code and overloaded the method as follows so that I can call the same code to check and request or just to check permissions as needed.

    public boolean checkAndRequestPermissions() {
        checkAndRequestPermissions(false);
    }
    
    public boolean checkAndRequestPermissions(boolean checkOnly) {
    
        Log.d("checkAndRequestPermissions", "starting check");
    
        int internet = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE);
        int loc_coarse = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION);
        int loc_fine = ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION);
        List<String> listPermissionsNeeded = new ArrayList<>();
    
        if (internet != PackageManager.PERMISSION_GRANTED) {
            Log.d("checkAndRequestPermissions", "INTERNET missing");
            listPermissionsNeeded.add(Manifest.permission.ACCESS_NETWORK_STATE);
        }
        if (loc_coarse != PackageManager.PERMISSION_GRANTED) {
            Log.d("checkAndRequestPermissions", "COARSE_LOCATION missing");
            listPermissionsNeeded.add(Manifest.permission.ACCESS_COARSE_LOCATION);
        }
        if (loc_fine != PackageManager.PERMISSION_GRANTED) {
            Log.d("checkAndRequestPermissions", "FINE_LOCATION missing");
            listPermissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION);
        }
    
        if (!listPermissionsNeeded.isEmpty() && !checkOnly) {
            Log.d("checkAndRequestPermissions", "Requesting missing permissions");
            ActivityCompat.requestPermissions((Activity) this, listPermissionsNeeded.toArray
                    (new String[listPermissionsNeeded.size()]), 1);
            return false;
        }
        return true;
    }