Skip to content

Commit ee9c257

Browse files
authored
Merge pull request #2740 from misl6/release-2023.01.28
Release 2023.01.28
2 parents cc6481b + 5b45f40 commit ee9c257

File tree

15 files changed

+427
-72
lines changed

15 files changed

+427
-72
lines changed

CHANGELOG.md

+27
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
11
# Changelog
22

3+
## [v2023.01.28](https://github.com/kivy/python-for-android/tree/v2023.01.28) (2023-01-28)
4+
5+
[Full Changelog](https://github.com/kivy/python-for-android/compare/v2022.12.20...v2023.01.28)
6+
7+
**Closed issues:**
8+
9+
- Python
10+
[\#2737](https://github.com/kivy/python-for-android/issues/2737)
11+
- AndroidX Issue [\#2736](https://github.com/kivy/python-for-android/issues/2736)
12+
- Kivy build failed [\#2735](https://github.com/kivy/python-for-android/issues/2735)
13+
- Can't build apk using READ\_EXTERNAL\_STORAGE, WRITE\_EXTERNAL\_STORAGE in buildozer.spec [\#2732](https://github.com/kivy/python-for-android/issues/2732)
14+
- BUILD FAILURE: No main.py\(o\) found in your app directory. [\#2731](https://github.com/kivy/python-for-android/issues/2731)
15+
- Your app currently targets API level 30 and must target at least API level 31 to ensure that it is built on the latest APIs optimised for security and performance. Change your app's target API level to at least 31 [\#2729](https://github.com/kivy/python-for-android/issues/2729)
16+
- Your app currently targets API level 30 and must target at least API level 31 to ensure that it is built on the latest APIs optimised for security and performance. Change your app's target API level to at least 31 [\#2727](https://github.com/kivy/python-for-android/issues/2727)
17+
- `sh.CommandNotFound: ./download.sh` [\#2726](https://github.com/kivy/python-for-android/issues/2726)
18+
- Setting `android:screenOrientation` via `--orientation` has no effect when targeting API 31 [\#2724](https://github.com/kivy/python-for-android/issues/2724)
19+
- \[Question\]: How to set 'compileSdkVersion' to 31 or higher. [\#2722](https://github.com/kivy/python-for-android/issues/2722)
20+
- Bug in the keyboard event listener [\#2423](https://github.com/kivy/python-for-android/issues/2423)
21+
22+
**Merged pull requests:**
23+
24+
- Implements `--manifest-orientation` and changes how `--orientation` works so we can now pass the setting to the SDL orientation hint [\#2739](https://github.com/kivy/python-for-android/pull/2739) ([misl6](https://github.com/misl6))
25+
- Update \_\_init\_\_.py from `scrypt` recipe [\#2738](https://github.com/kivy/python-for-android/pull/2738) ([FilipeMarch](https://github.com/FilipeMarch))
26+
- Apply a patch from SDL upstream that fixes orientation settings [\#2730](https://github.com/kivy/python-for-android/pull/2730) ([misl6](https://github.com/misl6))
27+
- Support permission properties \(`maxSdkVersion` and `usesPermissionFlags`\) + remove `WRITE_EXTERNAL_STORAGE` permission, which has been previously declared by default [\#2725](https://github.com/kivy/python-for-android/pull/2725) ([misl6](https://github.com/misl6))
28+
- Merge master in develop [\#2721](https://github.com/kivy/python-for-android/pull/2721) ([misl6](https://github.com/misl6))
29+
330
## [v2022.12.20](https://github.com/kivy/python-for-android/tree/v2022.12.20) (2022-12-20)
431

532
[Full Changelog](https://github.com/kivy/python-for-android/compare/v2022.09.04...v2022.12.20)

Makefile

+4-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ testapps-with-numpy: virtualenv
4040
. $(ACTIVATE) && cd testapps/on_device_unit_tests/ && \
4141
python setup.py apk --sdk-dir $(ANDROID_SDK_HOME) --ndk-dir $(ANDROID_NDK_HOME) \
4242
--requirements libffi,sdl2,pyjnius,kivy,python3,openssl,requests,urllib3,chardet,idna,sqlite3,setuptools,numpy \
43-
--arch=armeabi-v7a --arch=arm64-v8a --arch=x86_64 --arch=x86
43+
--arch=armeabi-v7a --arch=arm64-v8a --arch=x86_64 --arch=x86 \
44+
--permission "(name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)" --permission "(name=android.permission.INTERNET)"
4445

4546
testapps-with-scipy: virtualenv
4647
. $(ACTIVATE) && cd testapps/on_device_unit_tests/ && \
@@ -53,7 +54,8 @@ testapps-with-numpy-aab: virtualenv
5354
. $(ACTIVATE) && cd testapps/on_device_unit_tests/ && \
5455
python setup.py aab --sdk-dir $(ANDROID_SDK_HOME) --ndk-dir $(ANDROID_NDK_HOME) \
5556
--requirements libffi,sdl2,pyjnius,kivy,python3,openssl,requests,urllib3,chardet,idna,sqlite3,setuptools,numpy \
56-
--arch=armeabi-v7a --arch=arm64-v8a --arch=x86_64 --arch=x86 --release
57+
--arch=armeabi-v7a --arch=arm64-v8a --arch=x86_64 --arch=x86 --release \
58+
--permission "(name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)" --permission "(name=android.permission.INTERNET)"
5759

5860
testapps-service_library-aar: virtualenv
5961
. $(ACTIVATE) && cd testapps/on_device_unit_tests/ && \

doc/source/buildoptions.rst

+39-15
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,36 @@ options (this list may not be exhaustive):
5757
- ``--package``: The Java package name for your project. e.g. ``org.example.yourapp``.
5858
- ``--name``: The app name.
5959
- ``--version``: The version number.
60-
- ``--orientation``: Usually one of ``portait``, ``landscape``,
61-
``sensor`` to automatically rotate according to the device
62-
orientation, or ``user`` to do the same but obeying the user's
63-
settings. The full list of valid options is given under
64-
``android:screenOrientation`` in the `Android documentation
65-
<https://developer.android.com/guide/topics/manifest/activity-element.html>`__.
60+
- ``--orientation``: The orientations that the app will display in.
61+
(Available options are ``portrait``, ``landscape``, ``portrait-reverse``, ``landscape-reverse``).
62+
Since Android ignores ``android:screenOrientation`` when in multi-window mode
63+
(Which is the default on Android 12+), this option will also set the window orientation hints
64+
for the SDL bootstrap. If multiple orientations are given,
65+
``android:screenOrientation`` will be set to ``unspecified``.
66+
- ``--manifest-orientation``: The orientation that will be set for the ``android:screenOrientation``
67+
attribute of the activity in the ``AndroidManifest.xml`` file. If not set, the value
68+
will be synthesized from the ``--orientation`` option.
69+
The full list of valid options is given under ``android:screenOrientation``
70+
in the `Android documentation <https://developer.android.com/guide/topics/manifest/activity-element.html>`__.
6671
- ``--icon``: A path to the png file to use as the application icon.
67-
- ``--permission``: A permission name for the app,
68-
e.g. ``--permission VIBRATE``. For multiple permissions, add
69-
multiple ``--permission`` arguments.
72+
- ``--permission``: A permission that needs to be declared into the App ``AndroidManifest.xml``.
73+
For multiple permissions, add multiple ``--permission`` arguments.
74+
75+
.. Note ::
76+
``--permission`` accepts the following syntaxes:
77+
``--permission (name=android.permission.WRITE_EXTERNAL_STORAGE;maxSdkVersion=18)``
78+
or ``--permission android.permission.WRITE_EXTERNAL_STORAGE``.
79+
80+
The first syntax is used to set additional properties to the permission
81+
(``android:maxSdkVersion`` and ``android:usesPermissionFlags`` are the only ones supported for now).
82+
83+
The second one can be used when there's no need to add any additional properties.
84+
85+
.. Warning ::
86+
The syntax ``--permission VIBRATE`` (only the permission name, without the prefix),
87+
is also supported for backward compatibility, but it will be removed in the future.
88+
89+
7090
- ``--meta-data``: Custom key=value pairs to add in the application metadata.
7191
- ``--presplash``: A path to the image file to use as a screen while
7292
the application is loading.
@@ -121,12 +141,16 @@ ready.
121141
- ``--package``: The Java package name for your project. e.g. ``org.example.yourapp``.
122142
- ``--name``: The app name.
123143
- ``--version``: The version number.
124-
- ``--orientation``: Usually one of ``portait``, ``landscape``,
125-
``sensor`` to automatically rotate according to the device
126-
orientation, or ``user`` to do the same but obeying the user's
127-
settings. The full list of valid options is given under
128-
``android:screenOrientation`` in the `Android documentation
129-
<https://developer.android.com/guide/topics/manifest/activity-element.html>`__.
144+
- ``--orientation``: The orientations that the app will display in.
145+
(Available options are ``portrait``, ``landscape``, ``portrait-reverse``, ``landscape-reverse``).
146+
Since Android ignores ``android:screenOrientation`` when in multi-window mode
147+
(Which is the default on Android 12+), this setting is not guaranteed to work, and
148+
you should consider to implement a custom orientation change handler in your app.
149+
- ``--manifest-orientation``: The orientation that will be set in the ``android:screenOrientation``
150+
attribute of the activity in the ``AndroidManifest.xml`` file. If not set, the value
151+
will be synthesized from the ``--orientation`` option.
152+
The full list of valid options is given under ``android:screenOrientation``
153+
in the `Android documentation <https://developer.android.com/guide/topics/manifest/activity-element.html>`__.
130154
- ``--icon``: A path to the png file to use as the application icon.
131155
- ``--permission``: A permission name for the app,
132156
e.g. ``--permission VIBRATE``. For multiple permissions, add

pythonforandroid/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = '2022.12.20'
1+
__version__ = '2023.01.28'

pythonforandroid/bdistapk.py

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ def finalize_options(self):
4343
if option == 'permissions':
4444
for perm in value:
4545
sys.argv.append('--permission={}'.format(perm))
46+
elif option == 'orientation':
47+
for orient in value:
48+
sys.argv.append('--orientation={}'.format(orient))
4649
elif value in (None, 'None'):
4750
sys.argv.append('--{}'.format(option))
4851
else:

pythonforandroid/bootstraps/common/build/build.py

+127-30
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,6 @@ def get_bootstrap_name():
5353

5454
curdir = dirname(__file__)
5555

56-
PYTHON = get_hostpython()
57-
if PYTHON is not None and not exists(PYTHON):
58-
PYTHON = None
59-
6056
BLACKLIST_PATTERNS = [
6157
# code versionning
6258
'^*.hg/*',
@@ -75,9 +71,19 @@ def get_bootstrap_name():
7571
]
7672

7773
WHITELIST_PATTERNS = []
78-
if get_bootstrap_name() in ('sdl2', 'webview', 'service_only'):
79-
WHITELIST_PATTERNS.append('pyconfig.h')
8074

75+
if os.environ.get("P4A_BUILD_IS_RUNNING_UNITTESTS", "0") != "1":
76+
PYTHON = get_hostpython()
77+
_bootstrap_name = get_bootstrap_name()
78+
else:
79+
PYTHON = "python3"
80+
_bootstrap_name = "sdl2"
81+
82+
if PYTHON is not None and not exists(PYTHON):
83+
PYTHON = None
84+
85+
if _bootstrap_name in ('sdl2', 'webview', 'service_only'):
86+
WHITELIST_PATTERNS.append('pyconfig.h')
8187

8288
environment = jinja2.Environment(loader=jinja2.FileSystemLoader(
8389
join(curdir, 'templates')))
@@ -243,8 +249,8 @@ def make_package(args):
243249
with open(os.path.join(env_vars_tarpath, "p4a_env_vars.txt"), "w") as f:
244250
if hasattr(args, "window"):
245251
f.write("P4A_IS_WINDOWED=" + str(args.window) + "\n")
246-
if hasattr(args, "orientation"):
247-
f.write("P4A_ORIENTATION=" + str(args.orientation) + "\n")
252+
if hasattr(args, "sdl_orientation_hint"):
253+
f.write("KIVY_ORIENTATION=" + str(args.sdl_orientation_hint) + "\n")
248254
f.write("P4A_NUMERIC_VERSION=" + str(args.numeric_version) + "\n")
249255
f.write("P4A_MINSDK=" + str(args.min_sdk_version) + "\n")
250256

@@ -646,20 +652,92 @@ def make_package(args):
646652
subprocess.check_output(patch_command)
647653

648654

649-
def parse_args_and_make_package(args=None):
650-
global BLACKLIST_PATTERNS, WHITELIST_PATTERNS, PYTHON
655+
def parse_permissions(args_permissions):
656+
if args_permissions and isinstance(args_permissions[0], list):
657+
args_permissions = [p for perm in args_permissions for p in perm]
658+
659+
def _is_advanced_permission(permission):
660+
return permission.startswith("(") and permission.endswith(")")
661+
662+
def _decode_advanced_permission(permission):
663+
SUPPORTED_PERMISSION_PROPERTIES = ["name", "maxSdkVersion", "usesPermissionFlags"]
664+
_permission_args = permission[1:-1].split(";")
665+
_permission_args = (arg.split("=") for arg in _permission_args)
666+
advanced_permission = dict(_permission_args)
667+
668+
if "name" not in advanced_permission:
669+
raise ValueError("Advanced permission must have a name property")
670+
671+
for key in advanced_permission.keys():
672+
if key not in SUPPORTED_PERMISSION_PROPERTIES:
673+
raise ValueError(
674+
f"Property '{key}' is not supported. "
675+
"Advanced permission only supports: "
676+
f"{', '.join(SUPPORTED_PERMISSION_PROPERTIES)} properties"
677+
)
678+
679+
return advanced_permission
680+
681+
_permissions = []
682+
for permission in args_permissions:
683+
if _is_advanced_permission(permission):
684+
_permissions.append(_decode_advanced_permission(permission))
685+
else:
686+
if "." in permission:
687+
_permissions.append(dict(name=permission))
688+
else:
689+
_permissions.append(dict(name=f"android.permission.{permission}"))
690+
return _permissions
691+
692+
693+
def get_sdl_orientation_hint(orientations):
694+
SDL_ORIENTATION_MAP = {
695+
"landscape": "LandscapeLeft",
696+
"portrait": "Portrait",
697+
"portrait-reverse": "PortraitUpsideDown",
698+
"landscape-reverse": "LandscapeRight",
699+
}
700+
return " ".join(
701+
[SDL_ORIENTATION_MAP[x] for x in orientations if x in SDL_ORIENTATION_MAP]
702+
)
651703

704+
705+
def get_manifest_orientation(orientations, manifest_orientation=None):
706+
# If the user has specifically set an orientation to use in the manifest,
707+
# use that.
708+
if manifest_orientation is not None:
709+
return manifest_orientation
710+
711+
# If multiple or no orientations are specified, use unspecified in the manifest,
712+
# as we can only specify one orientation in the manifest.
713+
if len(orientations) != 1:
714+
return "unspecified"
715+
716+
# Convert the orientation to a value that can be used in the manifest.
717+
# If the specified orientation is not supported, use unspecified.
718+
MANIFEST_ORIENTATION_MAP = {
719+
"landscape": "landscape",
720+
"portrait": "portrait",
721+
"portrait-reverse": "reversePortrait",
722+
"landscape-reverse": "reverseLandscape",
723+
}
724+
return MANIFEST_ORIENTATION_MAP.get(orientations[0], "unspecified")
725+
726+
727+
def get_dist_ndk_min_api_level():
652728
# Get the default minsdk, equal to the NDK API that this dist is built against
653729
try:
654730
with open('dist_info.json', 'r') as fileh:
655731
info = json.load(fileh)
656-
default_min_api = int(info['ndk_api'])
657-
ndk_api = default_min_api
732+
ndk_api = int(info['ndk_api'])
658733
except (OSError, KeyError, ValueError, TypeError):
659734
print('WARNING: Failed to read ndk_api from dist info, defaulting to 12')
660-
default_min_api = 12 # The old default before ndk_api was introduced
661-
ndk_api = 12
735+
ndk_api = 12 # The old default before ndk_api was introduced
736+
return ndk_api
737+
662738

739+
def create_argument_parser():
740+
ndk_api = get_dist_ndk_min_api_level()
663741
import argparse
664742
ap = argparse.ArgumentParser(description='''\
665743
Package a Python application for Android (using
@@ -742,19 +820,21 @@ def parse_args_and_make_package(args=None):
742820
ap.add_argument('--window', dest='window', action='store_true',
743821
default=False,
744822
help='Indicate if the application will be windowed')
823+
ap.add_argument('--manifest-orientation', dest='manifest_orientation',
824+
help=('The orientation that will be set in the '
825+
'android:screenOrientation attribute of the activity '
826+
'in the AndroidManifest.xml file. If not set, '
827+
'the value will be synthesized from the --orientation option.'))
745828
ap.add_argument('--orientation', dest='orientation',
746-
default='portrait',
747-
help=('The orientation that the game will '
748-
'display in. '
749-
'Usually one of "landscape", "portrait", '
750-
'"sensor", or "user" (the same as "sensor" '
751-
'but obeying the '
752-
'user\'s Android rotation setting). '
753-
'The full list of options is given under '
754-
'android_screenOrientation at '
755-
'https://developer.android.com/guide/'
756-
'topics/manifest/'
757-
'activity-element.html'))
829+
action="append", default=[],
830+
choices=['portrait', 'landscape', 'landscape-reverse', 'portrait-reverse'],
831+
help=('The orientations that the app will display in. '
832+
'Since Android ignores android:screenOrientation '
833+
'when in multi-window mode (Which is the default on Android 12+), '
834+
'this option will also set the window orientation hints '
835+
'for apps using the (default) SDL bootstrap.'
836+
'If multiple orientations are given, android:screenOrientation '
837+
'will be set to "unspecified"'))
758838

759839
ap.add_argument('--enable-androidx', dest='enable_androidx',
760840
action='store_true',
@@ -809,9 +889,9 @@ def parse_args_and_make_package(args=None):
809889
ap.add_argument('--sdk', dest='sdk_version', default=-1,
810890
type=int, help=('Deprecated argument, does nothing'))
811891
ap.add_argument('--minsdk', dest='min_sdk_version',
812-
default=default_min_api, type=int,
892+
default=ndk_api, type=int,
813893
help=('Minimum Android SDK version that the app supports. '
814-
'Defaults to {}.'.format(default_min_api)))
894+
'Defaults to {}.'.format(ndk_api)))
815895
ap.add_argument('--allow-minsdk-ndkapi-mismatch', default=False,
816896
action='store_true',
817897
help=('Allow the --minsdk argument to be different from '
@@ -874,6 +954,15 @@ def parse_args_and_make_package(args=None):
874954
ap.add_argument('--activity-class-name', dest='activity_class_name', default=DEFAULT_PYTHON_ACTIVITY_JAVA_CLASS,
875955
help='The full java class name of the main activity')
876956

957+
return ap
958+
959+
960+
def parse_args_and_make_package(args=None):
961+
global BLACKLIST_PATTERNS, WHITELIST_PATTERNS, PYTHON
962+
963+
ndk_api = get_dist_ndk_min_api_level()
964+
ap = create_argument_parser()
965+
877966
# Put together arguments, and add those from .p4a config file:
878967
if args is None:
879968
args = sys.argv[1:]
@@ -918,8 +1007,14 @@ def _read_configuration():
9181007
'deprecated and does nothing.')
9191008
args.sdk_version = -1 # ensure it is not used
9201009

921-
if args.permissions and isinstance(args.permissions[0], list):
922-
args.permissions = [p for perm in args.permissions for p in perm]
1010+
args.permissions = parse_permissions(args.permissions)
1011+
1012+
args.manifest_orientation = get_manifest_orientation(
1013+
args.orientation, args.manifest_orientation
1014+
)
1015+
1016+
if get_bootstrap_name() == "sdl2":
1017+
args.sdl_orientation_hint = get_sdl_orientation_hint(args.orientation)
9231018

9241019
if args.res_xmls and isinstance(args.res_xmls[0], list):
9251020
args.res_xmls = [x for res in args.res_xmls for x in res]
@@ -959,4 +1054,6 @@ def _read_configuration():
9591054

9601055

9611056
if __name__ == "__main__":
1057+
if get_bootstrap_name() in ('sdl2', 'webview', 'service_only'):
1058+
WHITELIST_PATTERNS.append('pyconfig.h')
9621059
parse_args_and_make_package()

0 commit comments

Comments
 (0)