kivy / kivy/python-for-android

request_permissions() undocumented side effects

Open
#2,309 0 comments 0 reactions 0 assignees View on GitHub
bug
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.