1+ """Environment detection and Android component accessors.
2+
3+ This module provides functions to determine the environment in which the code is running (e.g., Kivy on Android, Flet app, etc.)
4+ And to access Android-specific components like the activity, service, notification manager, and storage paths.
5+
6+ It uses lazy initialization to keep the startup time at 0 and avoid errors in non-Android environments.
7+ """
8+
9+
110import os
211
312__version__ = "1.61.6"
413
514from .internal .logger import logger
615
16+
17+ _activity_class_name = None
18+
19+ _jnius = None
20+ _python_activity = None
21+ _python_service = None
22+ _activity_context = None
23+ _app_storage_path = None
24+ _package_name = None
25+ _androidx_dependency = None
26+
727def on_kivy_android ():
828 kivy_build = os .environ .get ('KIVY_BUILD' , '' )
9- if kivy_build in { 'android' } :
29+ if kivy_build == 'android' :
1030 return True
1131 elif 'P4A_BOOTSTRAP' in os .environ :
1232 return True
@@ -21,18 +41,27 @@ def on_flet_app():
2141
2242
2343def on_android_platform ():
24- return on_kivy_android () or on_flet_app ()
44+ return on_kivy_android () or bool ( on_flet_app () )
2545
2646
27- if on_android_platform ():
28- try :
29- from jnius import cast , autoclass
30- except ModuleNotFoundError :
47+ def _get_jnius ():
48+ global _jnius
49+
50+ if _jnius is not None :
51+ return _jnius
52+
53+ if on_android_platform ():
54+ try :
55+ from jnius import cast , autoclass
56+ except ModuleNotFoundError :
57+ cast = lambda x , y : x
58+ autoclass = lambda x : None
59+ else :
3160 cast = lambda x , y : x
3261 autoclass = lambda x : None
33- else :
34- cast = lambda x , y : x
35- autoclass = lambda x : None
62+
63+ _jnius = ( cast , autoclass )
64+ return _jnius
3665
3766
3867def on_pydroid_app ():
@@ -46,35 +75,55 @@ def on_pydroid_app():
4675 return False
4776
4877
78+
4979def has_androidx_dependency ():
50- """Check if androidx dependencies are available"""
80+ global _androidx_dependency
81+
82+ if _androidx_dependency is not None :
83+ return _androidx_dependency
84+
85+ if not on_android_platform ():
86+ _androidx_dependency = False
87+ return _androidx_dependency
88+
5189 try :
52- _ = autoclass ('androidx.core.app.NotificationCompat' )
53- return True
90+ _ , autoclass = _get_jnius ()
91+ autoclass ("androidx.core.app.NotificationCompat" )
92+ _androidx_dependency = True
5493 except Exception :
55- return False
94+ _androidx_dependency = False
95+
96+ return _androidx_dependency
5697
5798
5899def get_activity_class_name ():
59- ACTIVITY_CLASS_NAME = os .getenv ("MAIN_ACTIVITY_HOST_CLASS_NAME" ) # flet python
60- if not ACTIVITY_CLASS_NAME :
100+ global _activity_class_name
101+
102+ if _activity_class_name is not None :
103+ return _activity_class_name
104+
105+ activity_class_name = os .getenv ("MAIN_ACTIVITY_HOST_CLASS_NAME" ) # flet python
106+
107+ if not activity_class_name :
61108 try :
62109 # noinspection PyPackageRequirements
63110 from android import config # type: ignore
64- ACTIVITY_CLASS_NAME = config .JAVA_NAMESPACE
111+ activity_class_name = config .JAVA_NAMESPACE
65112 except (ImportError , AttributeError ):
66- ACTIVITY_CLASS_NAME = 'org.kivy.android'
67- return ACTIVITY_CLASS_NAME
113+ activity_class_name = "org.kivy.android"
114+
115+ _activity_class_name = activity_class_name
116+
117+ return _activity_class_name
68118
69119
70120def from_service_file ():
71121 return 'PYTHON_SERVICE_ARGUMENT' in os .environ
72122
73123
74- run_on_ui_thread = None
75124if on_flet_app () or from_service_file () or not on_android_platform ():
76125 def run_on_ui_thread (func ):
77- """Fallback for Developing on PC """
126+ """Fallback for development/non-Kivy environments. """
78127
79128 def wrapper (* args , ** kwargs ):
80129 logger .warning ("Simulating run on UI thread" )
@@ -87,46 +136,73 @@ def wrapper(*args, **kwargs):
87136
88137
89138def get_python_activity ():
139+ global _python_activity
140+
141+ if _python_activity is not None :
142+ return _python_activity
143+
90144 if not on_android_platform ():
91145 logger .warning ("Can't get python activity, Not on Android." )
92146 from .internal .facade import PythonActivity
93- return PythonActivity
94- ACTIVITY_CLASS_NAME = get_activity_class_name ()
147+ _python_activity = PythonActivity
148+ return _python_activity
149+
150+ _ , autoclass = _get_jnius ()
151+ activity_class_name = get_activity_class_name ()
152+
95153 if on_flet_app ():
96- PythonActivity = autoclass ( ACTIVITY_CLASS_NAME )
154+ class_name = activity_class_name
97155 else :
98- PythonActivity = autoclass (ACTIVITY_CLASS_NAME + '.PythonActivity' )
99- return PythonActivity
156+ class_name = activity_class_name + '.PythonActivity'
157+ _python_activity = autoclass (class_name )
158+ return _python_activity
159+
100160
101161
102162def get_python_service ():
163+ global _python_service
164+
165+ if _python_service is not None :
166+ return _python_service
167+
103168 if not on_android_platform ():
104169 from .internal .facade import PythonActivity
105170 logger .warning ("Can't get python service, Not on Android." )
106- return PythonActivity
171+ _python_service = PythonActivity
172+ return _python_service
173+
174+ _ , autoclass = _get_jnius ()
107175 PythonService = autoclass (get_activity_class_name () + '.PythonService' )
108- return PythonService .mService
176+ _python_service = PythonService .mService
177+ return _python_service
109178
110179
111180def get_python_activity_context ():
181+ global _activity_context
182+
183+ if _activity_context is not None :
184+ return _activity_context
185+
112186 if not on_android_platform ():
113187 logger .warning ("Can't get python context, Not on Android." )
114188 from .internal .facade import Context
115- return Context
189+ _activity_context = Context
190+ return _activity_context
116191
117- PythonActivity = get_python_activity ()
118192 if from_service_file ():
119193 service = get_python_service ()
120- context = service .getApplication ().getApplicationContext ()
194+ _activity_context = service .getApplication ().getApplicationContext ()
121195 else :
122- context = PythonActivity .mActivity
123- return context
196+ PythonActivity = get_python_activity ()
197+ _activity_context = PythonActivity .mActivity
198+ return _activity_context
124199
125200
126201def get_notification_manager ():
127202 if not on_android_platform ():
128203 logger .warning ("Can't get notification manager, Not on Android." )
129204 return None
205+ cast , autoclass = _get_jnius ()
130206 NotificationManager = autoclass ('android.app.NotificationManager' )
131207
132208 context = get_python_activity_context ()
@@ -135,16 +211,27 @@ def get_notification_manager():
135211
136212
137213def app_storage_path ():
214+ global _app_storage_path
215+
216+ if _app_storage_path is not None :
217+ return _app_storage_path
218+
138219 if on_flet_app ():
139220 context = get_python_activity_context ()
140- return os .path .join (context .getFilesDir ().getAbsolutePath (), 'flet' )
221+ _app_storage_path = os .path .join (context .getFilesDir ().getAbsolutePath (), 'flet' )
141222 elif on_kivy_android ():
142223 # noinspection PyPackageRequirements
143224 from android .storage import app_storage_path as kivy_app_storage_path # type: ignore
144- return kivy_app_storage_path ()
225+ _app_storage_path = kivy_app_storage_path ()
145226 else :
146- return os .getcwd () # TODO return file main.py path (not android)
227+ _app_storage_path = os .getcwd ()
228+ return _app_storage_path
147229
148230
149231def get_package_name ():
150- return get_python_activity_context ().getPackageName () # package.domain + "." + package.name
232+ global _package_name
233+
234+ if _package_name is not None :
235+ return _package_name
236+ _package_name = get_python_activity_context ().getPackageName ()
237+ return _package_name
0 commit comments