kivy / kivy/python-for-android
request_permissions() undocumented side effects
- Dominant language
- Python
- Stars
- 8.9k
- Forks
- 2k
- Avg merge
- 12h 20m
- Merged PRs (30d)
- 9
Description
### 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:
```sh
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
```
Contributor guide
Research direction
Start with the supplied runnable example and the request_permissions() entry point, then reproduce it using the shown buildozer.spec and `buildozer android debug` command. Trace the Android lifecycle callbacks around on_start(), on_pause(), on_resume(), and the permission callback; done means the observed behavior and safe usage are either corrected or documented clearly.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- android, python
- Domain
- mobile-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100