python-for-android icon indicating copy to clipboard operation
python-for-android copied to clipboard

request_permissions() undocumented side effects

Open RobertFlatt opened this issue 5 years ago • 0 comments

Checklist

  • [x ] the issue is indeed a bug and not a support request
  • [x ] issue doesn't already exist: https://github.com/kivy/python-for-android/issues
  • [x ] I have a short, runnable example that reproduces the issue
  • [x ] I reproduced the problem with the latest development version (p4a.branch = develop)
  • [ x] I used the grave accent (aka backticks) to format code or logs when appropriated

Versions

  • Python: 3.8
  • OS: Android 10
  • Kivy: 1.11.1
  • Cython: 29
  • OpenJDK: 8

Description

Calling request_permissions() from on_start() generates extra on_pause() and on_resume() events.

This can lead to unexpected behavior.

  1. If on_pause() returns False, the app immediately stops with no user action
  2. If on_pause() returns True, the app executes the permission callback between an on_pause() and an on_resume(). So on_resume() cannot assume the on_pause() state is its entry state.

The test case:

from kivy.app import App
from kivy.uix.label import Label
from android.permissions import request_permissions,Permission

class MyApp(App):
    def build(self):
        print('========build')
        return Label(text='Greetings Earthlings')

    def on_start(self):
        print('========start')
        # Comment this next call for test A) only
        request_permissions([Permission.ACCESS_FINE_LOCATION,
                             Permission.ACCESS_WIFI_STATE,
                             Permission.CHANGE_WIFI_STATE],
                            self.callback)

    def callback(self,permissions,grants):
        print('========callback')

    def on_pause(self):
        print('========pause')
        # Change to False for test B) only 
        return True

    def on_resume(self):
        print('========resume')

    def on_stop(self):
        # See https://github.com/kivy/python-for-android/issues/2272
        print('========stop')


MyApp().run()


Three cases illustrate the issue, at no time is pause initiated by the user:

A) Normal behavior: request_permissions() is commented, stop initiated with the back (<) button:

09-05 16:08:45.475 24087 24119 I python  : ========build
09-05 16:08:45.615 24087 24119 I python  : ========start
09-05 16:08:48.370 24087 24119 I python  : ========stop

B) Case 1) above: request_permissions() is not commented, on_pause() returns False, stop is automatic and instantaneous.

09-05 16:10:43.832 24230 24260 I python  : ========build
09-05 16:10:43.958 24230 24260 I python  : ========start
09-05 16:10:44.002 24230 24230 I python  : ========pause
09-05 16:10:44.030 24230 24260 I python  : ========stop

C) Case 2) above request_permissions() is not commented, on_pause() returns True, the callback() can change app state between on_pause() and on_resume(), stop is initiated with the back (<) button.

09-05 16:13:10.734 24344 24376 I python  : ========build
09-05 16:13:10.862 24344 24376 I python  : ========start
09-05 16:13:10.906 24344 24344 I python  : ========pause
09-05 16:13:10.950 24344 24344 I python  : ========callback
09-05 16:13:10.953 24344 24344 I python  : ========resume
09-05 16:13:15.443 24344 24376 I python  : ========stop

Moving request_permissions to build() removes the extra pause/resume but results in variable behavior, which the user must explicitly code for.

First execution, when the dialog appears:

09-05 16:39:59.970 25253 25279 I python  : ========build
09-05 16:40:00.155 25253 25279 I python  : ========start
09-05 16:40:02.529 25253 25253 I python  : ========callback
09-05 16:40:07.814 25253 25279 I python  : ========stop

Subsequent executions:

09-05 16:34:27.596 24876 24907 I python  : ========build
09-05 16:34:27.690 24876 24876 I python  : ========callback
09-05 16:34:27.775 24876 24907 I python  : ========start
09-05 16:34:33.171 24876 24907 I python  : ========stop

Also anecdotally calling request_permissions outside of a class results in unexpected calls (by Android) at on_resume() and subsequent non-deterministic behavior.

At a minimum the safe usage of request_permissions() is undocumented, and the usage reminds me of a minefield.

A loosely related issue #2272 addresses the inconsistent behavior of on_stop()

buildozer.spec

Command:

buildozer android debug

Spec file:

default buildozer.spec except:
android.permissions = ACCESS_FINE_LOCATION, CHANGE_WIFI_STATE, ACCESS_WIFI_STATE
p4a.branch = develop

Logs

see tests above

RobertFlatt avatar Sep 06 '20 03:09 RobertFlatt