Skip to content

Commit 9cd5220

Browse files
authored
Add support for display cutouts in manifest and add methods to retrieve data (#2969)
* Fresh changes of the display-cutout functionality * Fine tuning + added tools * Updated lib * Add missing None for default value while grabbing the sizes
1 parent 4c5fff6 commit 9cd5220

File tree

9 files changed

+112
-0
lines changed

9 files changed

+112
-0
lines changed

doc/source/buildoptions.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@ options (this list may not be exhaustive):
7272
- ``--permission``: A permission that needs to be declared into the App ``AndroidManifest.xml``.
7373
For multiple permissions, add multiple ``--permission`` arguments.
7474
``--home-app`` Gives you the option to set your application as a home app (launcher) on your Android device.
75+
``--display-cutout``: A display cutout is an area on some devices that extends into the display surface.
76+
It allows for an edge-to-edge experience while providing space for important sensors on the front of the device.
77+
(Available options are ``default``, ``shortEdges``, ``never`` and defaults to ``never``)
78+
`Android documentation <https://developer.android.com/develop/ui/views/layout/display-cutout>`__.
7579

7680
.. Note ::
7781
``--permission`` accepts the following syntaxes:

pythonforandroid/bootstraps/common/build/build.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,9 @@ def create_argument_parser():
793793
'launcher, rather than a single app.'))
794794
ap.add_argument('--home-app', dest='home_app', action='store_true', default=False,
795795
help=('Turn your application into a home app (launcher)'))
796+
ap.add_argument('--display-cutout', dest='display_cutout', default='never',
797+
help=('Enables display-cutout that renders around the area (notch) on '
798+
'some devices that extends into the display surface'))
796799
ap.add_argument('--permission', dest='permissions', action='append', default=[],
797800
help='The permissions to give this app.', nargs='+')
798801
ap.add_argument('--meta-data', dest='meta_data', action='append', default=[],

pythonforandroid/bootstraps/qt/build/templates/AndroidManifest.tmpl.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale|uiMode{% if args.min_sdk_version >= 8 %}|uiMode{% endif %}{% if args.min_sdk_version >= 13 %}|screenSize|smallestScreenSize{% endif %}{% if args.min_sdk_version >= 17 %}|layoutDirection{% endif %}{% if args.min_sdk_version >= 24 %}|density{% endif %}"
6262
android:screenOrientation="{{ args.manifest_orientation }}"
6363
android:exported="true"
64+
android:theme="@style/KivySupportCutout"
6465
{% if args.activity_launch_mode %}
6566
android:launchMode="{{ args.activity_launch_mode }}"
6667
{% endif %}

pythonforandroid/bootstraps/qt/build/templates/strings.tmpl.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
3+
<style name="KivySupportCutout">
4+
<item name="android:windowNoTitle">true</item>
5+
<!-- Display cutout is an area on some devices that extends into the display surface -->
6+
{% if args.display_cutout != 'never'%}
7+
<item name="android:windowLayoutInDisplayCutoutMode">{{ args.display_cutout }}</item>
8+
<item name="android:windowTranslucentStatus">true</item>
9+
<item name="android:windowTranslucentNavigation">true</item>
10+
<item name="android:windowFullscreen">true</item>
11+
{% endif %}
12+
</style>
313
<string name="app_name">{{ args.name }}</string>
414
<string name="private_version">{{ private_version }}</string>
515
<string name="presplash_color">{{ args.presplash_color }}</string>

pythonforandroid/bootstraps/sdl2/build/templates/AndroidManifest.tmpl.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale|uiMode{% if args.min_sdk_version >= 8 %}|uiMode{% endif %}{% if args.min_sdk_version >= 13 %}|screenSize|smallestScreenSize{% endif %}{% if args.min_sdk_version >= 17 %}|layoutDirection{% endif %}{% if args.min_sdk_version >= 24 %}|density{% endif %}"
7171
android:screenOrientation="{{ args.manifest_orientation }}"
7272
android:exported="true"
73+
android:theme="@style/KivySupportCutout"
7374
{% if args.activity_launch_mode %}
7475
android:launchMode="{{ args.activity_launch_mode }}"
7576
{% endif %}

pythonforandroid/bootstraps/sdl2/build/templates/strings.tmpl.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
3+
<style name="KivySupportCutout">
4+
<item name="android:windowNoTitle">true</item>
5+
<!-- Display cutout is an area on some devices that extends into the display surface -->
6+
{% if args.display_cutout != 'never'%}
7+
<item name="android:windowLayoutInDisplayCutoutMode">{{ args.display_cutout }}</item>
8+
<item name="android:windowTranslucentStatus">true</item>
9+
<item name="android:windowTranslucentNavigation">true</item>
10+
<item name="android:windowFullscreen">true</item>
11+
{% endif %}
12+
</style>
313
<string name="app_name">{{ args.name }}</string>
414
<string name="private_version">{{ private_version }}</string>
515
<string name="presplash_color">{{ args.presplash_color }}</string>

pythonforandroid/bootstraps/webview/build/templates/AndroidManifest.tmpl.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale|uiMode{% if args.min_sdk_version >= 8 %}|uiMode{% endif %}{% if args.min_sdk_version >= 13 %}|screenSize|smallestScreenSize{% endif %}{% if args.min_sdk_version >= 17 %}|layoutDirection{% endif %}{% if args.min_sdk_version >= 24 %}|density{% endif %}"
6363
android:screenOrientation="{{ args.manifest_orientation }}"
6464
android:exported="true"
65+
android:theme="@style/KivySupportCutout"
6566
{% if args.activity_launch_mode %}
6667
android:launchMode="{{ args.activity_launch_mode }}"
6768
{% endif %}

pythonforandroid/bootstraps/webview/build/templates/strings.tmpl.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<resources>
3+
<style name="KivySupportCutout">
4+
<item name="android:windowNoTitle">true</item>
5+
<!-- Display cutout is an area on some devices that extends into the display surface -->
6+
{% if args.display_cutout != 'never'%}
7+
<item name="android:windowLayoutInDisplayCutoutMode">{{ args.display_cutout }}</item>
8+
<item name="android:windowTranslucentStatus">true</item>
9+
<item name="android:windowTranslucentNavigation">true</item>
10+
<item name="android:windowFullscreen">true</item>
11+
{% endif %}
12+
</style>
313
<string name="app_name">{{ args.name }}</string>
414
<string name="private_version">{{ private_version }}</string>
515
<string name="presplash_color">{{ args.presplash_color }}</string>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from jnius import autoclass
2+
from kivy.core.window import Window
3+
4+
from android import mActivity
5+
6+
__all__ = ('get_cutout_pos', 'get_cutout_size', 'get_width_of_bar',
7+
'get_height_of_bar', 'get_size_of_bar')
8+
9+
10+
def _core_cutout():
11+
decorview = mActivity.getWindow().getDecorView()
12+
cutout = decorview.rootWindowInsets.displayCutout
13+
14+
return cutout.boundingRects.get(0)
15+
16+
17+
def get_cutout_pos():
18+
""" Get position of the display-cutout.
19+
Returns integer for each positions (xy)
20+
"""
21+
try:
22+
cutout = _core_cutout()
23+
return int(cutout.left), Window.height - int(cutout.height())
24+
except Exception:
25+
# Doesn't have a camera builtin with the display
26+
return 0, 0
27+
28+
29+
def get_cutout_size():
30+
""" Get the size (xy) of the front camera.
31+
Returns size with float values
32+
"""
33+
try:
34+
cutout = _core_cutout()
35+
return float(cutout.width()), float(cutout.height())
36+
except Exception:
37+
# Doesn't have a camera builtin with the display
38+
return 0., 0.
39+
40+
41+
def get_height_of_bar(bar_target=None):
42+
""" Get the height of either statusbar or navigationbar
43+
bar_target = status or navigation and defaults to status
44+
"""
45+
bar_target = bar_target or 'status'
46+
47+
if bar_target not in ('status', 'navigation'):
48+
raise Exception("bar_target must be 'status' or 'navigation'")
49+
50+
try:
51+
displayMetrics = autoclass('android.util.DisplayMetrics')
52+
mActivity.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics())
53+
resources = mActivity.getResources()
54+
resourceId = resources.getIdentifier(f'{bar_target}_bar_height', 'dimen',
55+
'android')
56+
57+
return float(max(resources.getDimensionPixelSize(resourceId), 0))
58+
except Exception:
59+
# Getting the size is not supported on older Androids
60+
return 0.
61+
62+
63+
def get_width_of_bar(bar_target=None):
64+
" Get the width of the bar "
65+
return Window.width
66+
67+
68+
def get_size_of_bar(bar_target=None):
69+
""" Get the size of either statusbar or navigationbar
70+
bar_target = status or navigation and defaults to status
71+
"""
72+
return get_width_of_bar(), get_height_of_bar(bar_target)

0 commit comments

Comments
 (0)