sschilli
sschilli

Reputation: 2251

Why is onGeolocationPermissionsShowPrompt being called continuously?

I have an app that uses a WebView where sites may request to use the device's geolocation. I have the following in my main activity:

public void onGeolocationPermissionsShowPrompt(final String origin, final GeolocationPermissions.Callback callback) {
    m_geolocationCallback = null;
    m_geolocationOrigin = null;

    // If we don't have location permissions, we must request them first
    if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        // Show rationale if necessary
        if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION)) {

            new AlertDialog.Builder(MainActivity.this)
                    .setMessage(getString(R.string.permission_location_rationale, origin))
                    .setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            m_geolocationOrigin = origin;
                            m_geolocationCallback = callback;
                            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
                        }
                    })
                    .show();
        }
        else {
            m_geolocationOrigin = origin;
            m_geolocationCallback = callback;
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION);
        }
    }
    // Otherwise just tell webview that permission has been granted
    else {
        callback.invoke(origin, true, false);
    }
}

To handle the permission request result, MainActivity also has the following:

@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case PERMISSIONS_REQUEST_ACCESS_FINE_LOCATION:
            // Permission granted
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                if (m_geolocationCallback != null) {
                    m_geolocationCallback.invoke(m_geolocationOrigin, true, false);
                }
            }
            // Permission denied
            else {
                // In this case, the user checked "Don't ask again" and denied permission
                if (Build.VERSION.SDK_INT >= 23 && !shouldShowRequestPermissionRationale(permissions[0])) {
                    Toast.makeText(this, R.string.permission_location_denied, Toast.LENGTH_LONG).show();
                }

                if (m_geolocationCallback != null) {
                    m_geolocationCallback.invoke(m_geolocationOrigin, false, false);
                }
            }
            return;
    }
}

The issue I'm running into is that whenever a site requests to use geolocation and I deny it (resulting in invoke(origin, false false) being called), the onGeolocationPermissionsShowPrompt method is called immediately and I am stuck in a loop of endlessly denying permission to the app.

If I check "don't ask again" in the permission request, it works fine, but I want to be able to ask the user for permission again at a later point in time.

I've tried fixing this by changing my rejection callback invocation to m_geolocationCallback.invoke(m_geolocationOrigin, false, true), but this does not produce the desired effect. This will prevent stop the continuous calls to onGeolocationPermissionsShowPrompt, but it also means that the given origin can no longer use geolocation even if permissions are later enabled, and I found no way to undo this (even by uninstalling/reinstalling the app).

Any ideas on how to get around this issue?

Upvotes: 1

Views: 2236

Answers (2)

Junhua Zhu
Junhua Zhu

Reputation: 51

we can fix it like below:

// set param 'retain' true, to prevent permission request continuously
callback?.invoke(origin, isGranted, true)
if (!isGranted) {
    // clear permission state, so the user can request permission again
    Handler().postDelayed({ GeolocationPermissions.getInstance().clear(origin) }, 500)
}

Upvotes: 0

weiyin
weiyin

Reputation: 6979

This looks like a bug in Android Webview. The endless loop happens if callback.invoke is called asynchronously with granted=false, but does not occur if it is called synchronously inside onGeolocationPermissionsShowPrompt.

My workaround is to save the time when the user denies the geolocation permission. If onGeolocationPermissionsShowPrompt is called again within a small amount of time and checkSelfPermission does not return PERMISSION_GRANTED, run callback.invoke(origin, false, false) and do not re-prompt the user.

Upvotes: 1

Related Questions