android-notify 1.60.8.dev0__tar.gz → 1.60.9.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/PKG-INFO +5 -5
  2. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/README.md +4 -4
  3. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/config.py +1 -1
  4. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/internal/facade.py +68 -28
  5. android_notify-1.60.9.dev0/android_notify/internal/logger.py +95 -0
  6. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/internal/permissions.py +22 -7
  7. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/sword.py +9 -2
  8. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/test_notification_permission.py +0 -2
  9. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/widgets/texts.py +10 -4
  10. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify.egg-info/PKG-INFO +5 -5
  11. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/pyproject.toml +1 -1
  12. android_notify-1.60.8.dev0/android_notify/internal/logger.py +0 -61
  13. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/__init__.py +0 -0
  14. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/__main__.py +0 -0
  15. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/base.py +0 -0
  16. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/core.py +0 -0
  17. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/fallback-icons/flet-appicon.png +0 -0
  18. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/fallback-icons/pydroid3-appicon.png +0 -0
  19. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/internal/an_types.py +0 -0
  20. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/internal/android.py +0 -0
  21. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/internal/channels.py +0 -0
  22. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/internal/helper.py +0 -0
  23. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/internal/intents.py +0 -0
  24. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/internal/java_classes.py +0 -0
  25. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/styles.py +0 -0
  26. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/__init__.py +0 -0
  27. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/android_notify_test.py +0 -0
  28. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/base_test.py +0 -0
  29. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/flet/adv/main.py +0 -0
  30. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/flet/adv/tests/__init__.py +0 -0
  31. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/flet/adv/tests/test_android_notify_full.py +0 -0
  32. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/flet/basic/src/core.py +0 -0
  33. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/flet/basic/src/main.py +0 -0
  34. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/flet/flet-working/src/core.py +0 -0
  35. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/flet/flet-working/src/main.py +0 -0
  36. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/main.py +0 -0
  37. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/p4a/hook.py +0 -0
  38. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/serivces/wallpaper.py +0 -0
  39. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/test_basic_notifications.py +0 -0
  40. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/test_notification_actions.py +0 -0
  41. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/test_notification_appearance.py +0 -0
  42. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/test_notification_behavior.py +0 -0
  43. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/test_notification_channels.py +0 -0
  44. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/test_notification_clear.py +0 -0
  45. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/test_notification_progress.py +0 -0
  46. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/test_notification_sound.py +0 -0
  47. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/tests/test_notification_styles.py +0 -0
  48. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify/widgets/images.py +0 -0
  49. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify.egg-info/SOURCES.txt +0 -0
  50. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify.egg-info/dependency_links.txt +0 -0
  51. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify.egg-info/entry_points.txt +0 -0
  52. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify.egg-info/requires.txt +0 -0
  53. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/android_notify.egg-info/top_level.txt +0 -0
  54. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/docs/website/src/pages/data/laner_Sent.py +0 -0
  55. {android_notify-1.60.8.dev0 → android_notify-1.60.9.dev0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: android-notify
3
- Version: 1.60.8.dev0
3
+ Version: 1.60.9.dev0
4
4
  Summary: A Python package that simplifies creating Android notifications in Kivy and Flet apps.
5
5
  Author-email: Fabian <fector101@yahoo.com>
6
6
  License-Expression: MIT
@@ -81,7 +81,7 @@ In your **`buildozer.spec`** file, ensure you include the following:
81
81
 
82
82
  ```ini
83
83
  # Add pyjnius so ensure it's packaged with the build
84
- requirements = python3, kivy, pyjnius, android-notify==1.60.8.dev0
84
+ requirements = python3, kivy, pyjnius, android-notify==1.60.9.dev0
85
85
  # Add permission for notifications
86
86
  android.permissions = POST_NOTIFICATIONS
87
87
  ```
@@ -99,7 +99,7 @@ In your `pyproject.toml` file, ensure you include the following:
99
99
  ```toml
100
100
  [tool.flet.android]
101
101
  dependencies = [
102
- "pyjnius","android-notify==1.60.8.dev0"
102
+ "pyjnius","android-notify==1.60.9.dev0"
103
103
  ]
104
104
 
105
105
  [tool.flet.android.permission]
@@ -117,10 +117,10 @@ dependencies = [
117
117
  <br/>
118
118
 
119
119
  On the [pydroid 3](https://play.google.com/store/apps/details?id=ru.iiec.pydroid3) mobile app for running python code you can test some features.
120
- - In pip section where you're asked to insert `Libary name` paste `android-notify==1.60.8.dev0`
120
+ - In pip section where you're asked to insert `Libary name` paste `android-notify==1.60.9.dev0`
121
121
  - Minimal working example
122
122
  ```py
123
- # Testing with `android-notify==1.60.8.dev0` on pydroid
123
+ # Testing with `android-notify==1.60.9.dev0` on pydroid
124
124
  from kivy.app import App
125
125
  from kivy.uix.boxlayout import BoxLayout
126
126
  from kivy.uix.button import Button
@@ -58,7 +58,7 @@ In your **`buildozer.spec`** file, ensure you include the following:
58
58
 
59
59
  ```ini
60
60
  # Add pyjnius so ensure it's packaged with the build
61
- requirements = python3, kivy, pyjnius, android-notify==1.60.8.dev0
61
+ requirements = python3, kivy, pyjnius, android-notify==1.60.9.dev0
62
62
  # Add permission for notifications
63
63
  android.permissions = POST_NOTIFICATIONS
64
64
  ```
@@ -76,7 +76,7 @@ In your `pyproject.toml` file, ensure you include the following:
76
76
  ```toml
77
77
  [tool.flet.android]
78
78
  dependencies = [
79
- "pyjnius","android-notify==1.60.8.dev0"
79
+ "pyjnius","android-notify==1.60.9.dev0"
80
80
  ]
81
81
 
82
82
  [tool.flet.android.permission]
@@ -94,10 +94,10 @@ dependencies = [
94
94
  <br/>
95
95
 
96
96
  On the [pydroid 3](https://play.google.com/store/apps/details?id=ru.iiec.pydroid3) mobile app for running python code you can test some features.
97
- - In pip section where you're asked to insert `Libary name` paste `android-notify==1.60.8.dev0`
97
+ - In pip section where you're asked to insert `Libary name` paste `android-notify==1.60.9.dev0`
98
98
  - Minimal working example
99
99
  ```py
100
- # Testing with `android-notify==1.60.8.dev0` on pydroid
100
+ # Testing with `android-notify==1.60.9.dev0` on pydroid
101
101
  from kivy.app import App
102
102
  from kivy.uix.boxlayout import BoxLayout
103
103
  from kivy.uix.button import Button
@@ -1,6 +1,6 @@
1
1
  import os
2
2
 
3
- __version__ = "1.60.8.dev0"
3
+ __version__ = "1.60.9.dev0"
4
4
 
5
5
 
6
6
  from .internal.java_classes import autoclass, cast, NotificationManager
@@ -3,8 +3,10 @@ For autocomplete Storing and Safely Running on PC
3
3
  Also For Reference of Available Methods
4
4
  """
5
5
 
6
+ from enum import IntFlag, auto
6
7
  from android_notify.internal.logger import logger
7
8
 
9
+
8
10
  class Bundle:
9
11
  def putString(self, key, value):
10
12
  logger.debug(f"[MOCK] Bundle.putString called with key={key}, value={value}")
@@ -19,11 +21,16 @@ class String(str):
19
21
  return str.__new__(cls, value)
20
22
 
21
23
 
22
- class Intent:
23
- FLAG_ACTIVITY_NEW_TASK = 'FACADE_FLAG_ACTIVITY_NEW_TASK'
24
- CATEGORY_DEFAULT = 'FACADE_FLAG_CATEGORY_DEFAULT'
24
+
25
+
26
+ class Intent(IntFlag):
27
+ NONE = 0
28
+ FLAG_ACTIVITY_CLEAR_TOP = auto()
29
+ FLAG_ACTIVITY_NEW_TASK = auto()
30
+ FLAG_ACTIVITY_SINGLE_TOP = auto()
25
31
 
26
32
  def __init__(self, context='', activity=''):
33
+ self.IS = "FACADE"
27
34
  self.obj = {}
28
35
  logger.debug(f"[MOCK] Intent initialized with context={context}, activity={activity}")
29
36
 
@@ -132,12 +139,13 @@ class NotificationChannel:
132
139
  def setSound(self, sound_uri, _):
133
140
  logger.debug(f"[MOCK] NotificationChannel.setSound called, sound_uri={sound_uri}")
134
141
 
135
- def enableVibration(self,state):
142
+ def enableVibration(self, state):
136
143
  logger.debug(f"[MOCK] NotificationChannel.enableVibration called, state={state}")
137
144
 
138
- def setVibrationPattern(self,list_of_numbers):
145
+ def setVibrationPattern(self, list_of_numbers):
139
146
  logger.debug(f"[MOCK] NotificationChannel.setVibrationPattern called, list_of_numbers={list_of_numbers}")
140
147
 
148
+
141
149
  class IconCompat:
142
150
  @classmethod
143
151
  def createWithBitmap(cls, bitmap):
@@ -175,6 +183,7 @@ class NotificationManagerCompat:
175
183
  IMPORTANCE_MIN = ''
176
184
  IMPORTANCE_NONE = ''
177
185
 
186
+
178
187
  class AndroidNotification:
179
188
  DEFAULT_ALL = 3
180
189
  PRIORITY_HIGH = 4
@@ -182,6 +191,7 @@ class AndroidNotification:
182
191
  PRIORITY_LOW = ''
183
192
  PRIORITY_MIN = ''
184
193
 
194
+
185
195
  class NotificationCompat:
186
196
  DEFAULT_ALL = 3
187
197
  PRIORITY_HIGH = 4
@@ -201,76 +211,97 @@ class NotificationCompatBuilder:
201
211
  self.mActions = MActions()
202
212
  logger.debug(f"[MOCK] NotificationCompatBuilder initialized with context={context}, channel_id={channel_id}")
203
213
 
204
- def setProgress(self, max_value, current_value, endless):
214
+ @classmethod
215
+ def setProgress(cls, max_value, current_value, endless):
205
216
  logger.debug(f"[MOCK] setProgress called with max={max_value}, current={current_value}, endless={endless}")
206
217
 
207
- def setStyle(self, style):
218
+ @classmethod
219
+ def setStyle(cls, style):
208
220
  logger.debug(f"[MOCK] setStyle called with style={style}")
209
221
 
210
- def setContentTitle(self, title):
222
+ @classmethod
223
+ def setContentTitle(cls, title):
211
224
  logger.debug(f"[MOCK] setContentTitle called with title={title}")
212
225
 
213
- def setContentText(self, text):
226
+ @classmethod
227
+ def setContentText(cls, text):
214
228
  logger.debug(f"[MOCK] setContentText called with text={text}")
215
229
 
216
- def setSmallIcon(self, icon):
230
+ @classmethod
231
+ def setSmallIcon(cls, icon):
217
232
  logger.debug(f"[MOCK] setSmallIcon called with icon={icon}")
218
233
 
219
- def setLargeIcon(self, icon):
234
+ @classmethod
235
+ def setLargeIcon(cls, icon):
220
236
  logger.debug(f"[MOCK] setLargeIcon called with icon={icon}")
221
237
 
222
- def setAutoCancel(self, auto_cancel: bool):
238
+ @classmethod
239
+ def setAutoCancel(cls, auto_cancel: bool):
223
240
  logger.debug(f"[MOCK] setAutoCancel called with auto_cancel={auto_cancel}")
224
241
 
225
- def setPriority(self, priority):
242
+ @classmethod
243
+ def setPriority(cls, priority):
226
244
  logger.debug(f"[MOCK] setPriority called with priority={priority}")
227
245
 
228
- def setDefaults(self, defaults):
246
+ @classmethod
247
+ def setDefaults(cls, defaults):
229
248
  logger.debug(f"[MOCK] setDefaults called with defaults={defaults}")
230
249
 
231
- def setOngoing(self, persistent: bool):
250
+ @classmethod
251
+ def setOngoing(cls, persistent: bool):
232
252
  logger.debug(f"[MOCK] setOngoing called with persistent={persistent}")
233
253
 
234
- def setOnlyAlertOnce(self, state):
254
+ @classmethod
255
+ def setOnlyAlertOnce(cls, state):
235
256
  logger.debug(f"[MOCK] setOnlyAlertOnce called with state={state}")
236
257
 
237
- def build(self):
258
+ @classmethod
259
+ def build(cls):
238
260
  logger.debug("[MOCK] build called")
239
261
 
240
- def setContentIntent(self, pending_action_intent: PendingIntent):
262
+ @classmethod
263
+ def setContentIntent(cls, pending_action_intent: PendingIntent):
241
264
  logger.debug(f"[MOCK] setContentIntent called with {pending_action_intent}")
242
265
 
243
- def addAction(self, icon_int, action_text, pending_action_intent):
266
+ @classmethod
267
+ def addAction(cls, icon_int, action_text, pending_action_intent):
244
268
  logger.debug(
245
269
  f"[MOCK] addAction called with icon={icon_int}, text={action_text}, intent={pending_action_intent}"
246
270
  )
247
271
 
248
- def setShowWhen(self, state):
272
+ @classmethod
273
+ def setShowWhen(cls, state):
249
274
  logger.debug(f"[MOCK] setShowWhen called with state={state}")
250
275
 
251
- def setWhen(self, time_ms):
276
+ @classmethod
277
+ def setWhen(cls, time_ms):
252
278
  logger.debug(f"[MOCK] setWhen called with time_ms={time_ms}")
253
279
 
254
- def setCustomContentView(self, layout):
280
+ @classmethod
281
+ def setCustomContentView(cls, layout):
255
282
  logger.debug(f"[MOCK] setCustomContentView called with layout={layout}")
256
283
 
257
- def setCustomBigContentView(self, layout):
284
+ @classmethod
285
+ def setCustomBigContentView(cls, layout):
258
286
  logger.debug(f"[MOCK] setCustomBigContentView called with layout={layout}")
259
287
 
260
- def setSubText(self, text):
288
+ @classmethod
289
+ def setSubText(cls, text):
261
290
  logger.debug(f"[MOCK] setSubText called with text={text}")
262
291
 
263
- def setColor(self, color: Color) -> None:
292
+ @classmethod
293
+ def setColor(cls, color: Color) -> None:
264
294
  logger.debug(f"[MOCK] setColor called with color={color}")
265
295
 
266
- def setVibrate(self, state) -> None:
296
+ @classmethod
297
+ def setVibrate(cls, state) -> None:
267
298
  logger.debug(f"[MOCK] setVibrate called with state={state}")
268
299
 
269
300
 
270
301
  class NotificationCompatBigTextStyle:
271
- def bigText(self, body):
302
+ def bigText(cls, body):
272
303
  logger.debug(f"[MOCK] NotificationCompatBigTextStyle.bigText called with body={body}")
273
- return self
304
+ return cls
274
305
 
275
306
  def setBigContentTitle(self, title):
276
307
  logger.debug(f"[MOCK] NotificationCompatBigTextStyle.setBigContentTitle called with title={title}")
@@ -334,6 +365,15 @@ class PythonActivity:
334
365
  logger.debug("[MOCK] mActivity used")
335
366
  return MActivity()
336
367
 
368
+ @staticmethod
369
+ def startForeground(notification_id, builder_build, foreground_type):
370
+ logger.debug(
371
+ f"[MOCK] startForeground called with notification_id={notification_id}, builder.build()={builder_build}, foreground_type={foreground_type}")
372
+
373
+ def setAutoRestartService(self):
374
+ logger.debug("[MOCK] setAutoRestartService called")
375
+ return self
376
+
337
377
 
338
378
  class DummyIcon:
339
379
  icon = 101
@@ -0,0 +1,95 @@
1
+ import logging
2
+ import sys
3
+ import os
4
+
5
+
6
+ try:
7
+ from jnius import autoclass
8
+ except ModuleNotFoundError:
9
+ autoclass = lambda x: None
10
+
11
+
12
+ def on_kivy_android():
13
+ kivy_build = os.environ.get('KIVY_BUILD', '')
14
+ if kivy_build in {'android'}:
15
+ return True
16
+ elif 'P4A_BOOTSTRAP' in os.environ:
17
+ return True
18
+ elif 'ANDROID_ARGUMENT' in os.environ:
19
+ return True
20
+
21
+ return False
22
+
23
+
24
+ def on_flet_app():
25
+ return os.getenv("MAIN_ACTIVITY_HOST_CLASS_NAME")
26
+
27
+
28
+ def on_android_platform():
29
+ return on_kivy_android() or on_flet_app()
30
+
31
+
32
+ def android_print(msg):
33
+ msg = str(msg)
34
+ if on_android_platform():
35
+ Log = autoclass("android.util.Log")
36
+ Log.i("python", msg)
37
+ return None
38
+ print(msg)
39
+ return None
40
+
41
+
42
+ def kivy_logger_patch():
43
+ if not on_kivy_android():
44
+ return
45
+
46
+ handler = logging.StreamHandler(sys.stdout)
47
+ formatter = KivyColorFormatter()
48
+ handler.setFormatter(formatter)
49
+
50
+ # Avoid duplicate logs if root logger is configured
51
+ logger.propagate = False
52
+ logger.addHandler(handler)
53
+ logger._configured = True
54
+
55
+
56
+ class KivyColorFormatter(logging.Formatter):
57
+ COLORS = {
58
+ 'DEBUG': '\x1b[1;36m', # bold cyan
59
+ 'INFO': '\x1b[1;92m', # bold lime green
60
+ 'WARNING': '\x1b[1;93m', # bold yellow
61
+ 'ERROR': '\x1b[1;91m', # bold red
62
+ 'CRITICAL': '\x1b[1;95m', # bold magenta
63
+ }
64
+ RESET = '\x1b[0m'
65
+
66
+ def format(self, record):
67
+ level = record.levelname.ljust(7)
68
+ name = record.name.ljust(14)
69
+ msg = record.getMessage()
70
+
71
+ if getattr(sys.stdout, "isatty", lambda: False)():
72
+ color = self.COLORS.get(record.levelname, '')
73
+ level = f"{color}{level}{self.RESET}"
74
+
75
+ return f"[{level}] [{name}] {msg}"
76
+
77
+
78
+ logger = logging.getLogger("android_notify")
79
+ kivy_logger_patch()
80
+
81
+ env_level = os.getenv("ANDROID_NOTIFY_LOGLEVEL")
82
+ if env_level:
83
+ try:
84
+ logging.getLogger("android_notify").setLevel(getattr(logging, env_level.upper()))
85
+ except Exception as android_notify_loglevel_error:
86
+ android_print(f"android_notify_loglevel_error: {android_notify_loglevel_error}")
87
+
88
+
89
+
90
+ if __name__ == "__main__":
91
+ logger.debug("Debug message - should not appear with INFO level")
92
+ logger.info("Info message")
93
+ logger.warning("Warning message")
94
+ logger.error("Error message")
95
+ logger.critical("Critical message")
@@ -5,7 +5,7 @@ import os.path
5
5
 
6
6
  from .logger import logger
7
7
  from android_notify.config import on_android_platform, on_flet_app, get_python_activity_context
8
- from android_notify.internal.java_classes import autoclass, BuildVersion, Manifest, Intent, String, Settings, Uri, PackageManager
8
+ from android_notify.internal.java_classes import autoclass, BuildVersion, Manifest, Intent, String, Settings, Uri, PackageManager, NotificationManagerCompat
9
9
  from android_notify.internal.helper import execute_callback
10
10
 
11
11
 
@@ -17,8 +17,15 @@ def has_notification_permission():
17
17
  if not on_android_platform():
18
18
  return True
19
19
 
20
- if BuildVersion.SDK_INT < 33: # Android 12 below
21
- return True
20
+ if BuildVersion.SDK_INT < 33: # Android 12 and below
21
+ try:
22
+ # NotificationManagerCompat is actually NotificationManager from android_notify.internal.java_classes
23
+ context = get_python_activity_context()
24
+ nm = context.getSystemService(NotificationManagerCompat)
25
+ return nm.areNotificationsEnabled()
26
+ except Exception as error_checking_permission:
27
+ logger.exception(f"On Android 12 and below Error checking permission: {error_checking_permission}")
28
+ return None
22
29
 
23
30
  if on_flet_app():
24
31
  context = get_python_activity_context()
@@ -36,16 +43,23 @@ def ask_notification_permission(callback=None, set_requesting_state=None, legacy
36
43
  execute_callback(callback, True)
37
44
  return None
38
45
 
39
- if BuildVersion.SDK_INT < 33: # Android 12 below
40
- execute_callback(callback, True)
41
- logger.warning("On android 12 or less don't need permission")
42
- return None
43
46
 
44
47
  if has_notification_permission():
45
48
  execute_callback(callback, True)
46
49
  logger.warning("Already have permission to send notifications")
47
50
  return None
48
51
 
52
+ if BuildVersion.SDK_INT < 33: # Android 12 and below
53
+ logger.warning("""
54
+ Can't show popup below Android 13, Opening Notification setting...
55
+
56
+ Add in MDApp().on_resume():
57
+ >> if NotificationHandler.has_permission() and self.screen_manager:
58
+ >> self.screen_manager.current = "home_screen"
59
+ """)
60
+ open_notification_settings_screen()
61
+ return None
62
+
49
63
  if not is_first_permission_ask() and not can_show_permission_request_popup():
50
64
  logger.warning("""Permission to send notifications has been denied permanently.
51
65
  This can happen when the user denies permission twice from the popup.
@@ -124,6 +138,7 @@ def can_show_permission_request_popup():
124
138
  return False
125
139
 
126
140
  if BuildVersion.SDK_INT < 33:
141
+ logger.warning("On android 12 or less, Can't show permission request popup")
127
142
  return False
128
143
 
129
144
  return context.shouldShowRequestPermissionRationale(Manifest.POST_NOTIFICATIONS)
@@ -114,6 +114,8 @@ class Notification(BaseNotification):
114
114
  :param data_object:
115
115
  :return:
116
116
  """
117
+ if not on_android_platform():
118
+ return
117
119
  self.__called_set_data = True
118
120
  self.data_object = data_object
119
121
  action_name = str(self.name or self.__id)
@@ -413,7 +415,7 @@ class Notification(BaseNotification):
413
415
  """
414
416
  self.silent = silent or self.silent
415
417
  if on_android_platform():
416
- self.start_building(persistent, close_on_click)
418
+ self.fill_args(persistent=persistent, close_on_click=close_on_click)
417
419
  dispatch_notification(notification_id=self.__id, builder=self.builder, passed_check=self.passed_check)
418
420
 
419
421
  self.__send_logs()
@@ -426,6 +428,7 @@ class Notification(BaseNotification):
426
428
  persistent (bool): True To not remove Notification When User hits clears All notifications button
427
429
  close_on_click (bool): True if you want Notification to be removed when clicked
428
430
  """
431
+ # TODO: Remove this method - Check if Device is Android 12 or less and log to use regular .send()
429
432
  self.passed_check = True
430
433
  self.send(silent, persistent, close_on_click)
431
434
 
@@ -591,7 +594,11 @@ class Notification(BaseNotification):
591
594
 
592
595
  return set_sound(self.builder, res_sound_name)
593
596
 
594
- def start_building(self, persistent=False, close_on_click=True, silent: bool = False):
597
+ def fill_args(self, silent: bool = False, persistent=False, close_on_click=True):
598
+ """Name Makes More sense than start_building"""
599
+ return self.start_building(silent, persistent , close_on_click)
600
+
601
+ def start_building(self, silent: bool = False, persistent=False, close_on_click=True):
595
602
  # Main use is for foreground service, bypassing .notify in .send method to let service.startForeground(...) send it
596
603
  self.silent = silent or self.silent
597
604
  if not on_android_platform():
@@ -1,5 +1,3 @@
1
- # android_notify/tests/basic_notification_actions.py
2
-
3
1
  from android_notify import NotificationHandler
4
2
  from android_notify.internal.permissions import ask_notification_permission
5
3
  from android_notify.core import asks_permission_if_needed
@@ -3,7 +3,7 @@ Android Texts related logic
3
3
  """
4
4
 
5
5
  from android_notify.config import on_android_platform
6
- from android_notify.internal.java_classes import autoclass, String, NotificationCompatBigTextStyle, NotificationCompatInboxStyle
6
+ from android_notify.internal.java_classes import String, NotificationCompatBigTextStyle, NotificationCompatInboxStyle
7
7
 
8
8
 
9
9
  def set_big_text(builder, body, title="", summary=""):
@@ -48,8 +48,10 @@ def set_title(builder, title, using_layout=False):
48
48
  :param title: New Notification Title
49
49
  :param using_layout: Whether to use layout or not
50
50
  """
51
-
51
+ def log():
52
+ logger.info(f'new notification title: {title}')
52
53
  if not on_android_platform():
54
+ log()
53
55
  return None
54
56
 
55
57
  if using_layout:
@@ -58,7 +60,7 @@ def set_title(builder, title, using_layout=False):
58
60
  else:
59
61
  builder.setContentTitle(String(title))
60
62
 
61
- logger.info(f'new notification title: {title}')
63
+ log()
62
64
  return None
63
65
 
64
66
 
@@ -69,8 +71,11 @@ def set_message(builder, message, using_layout=False):
69
71
  :param message: New Notification message
70
72
  :param using_layout: Whether to use layout or not
71
73
  """
74
+ def log():
75
+ logger.info(f'new notification message: {message}')
72
76
 
73
77
  if not on_android_platform():
78
+ log()
74
79
  return None
75
80
 
76
81
  if using_layout:
@@ -79,7 +84,7 @@ def set_message(builder, message, using_layout=False):
79
84
  else:
80
85
  builder.setContentText(String(message))
81
86
 
82
- logger.info(f'new notification message: {message}')
87
+ log()
83
88
  return None
84
89
 
85
90
 
@@ -116,6 +121,7 @@ def setLayoutText(layout, text_id, text, color):
116
121
 
117
122
  def set_custom_colors(builder, title, message, title_color, message_color):
118
123
  # Load layout
124
+ from android_notify.internal.java_classes import autoclass
119
125
  NotificationCompatDecoratedCustomViewStyle = autoclass(
120
126
  'android.app.Notification$DecoratedCustomViewStyle')
121
127
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: android-notify
3
- Version: 1.60.8.dev0
3
+ Version: 1.60.9.dev0
4
4
  Summary: A Python package that simplifies creating Android notifications in Kivy and Flet apps.
5
5
  Author-email: Fabian <fector101@yahoo.com>
6
6
  License-Expression: MIT
@@ -81,7 +81,7 @@ In your **`buildozer.spec`** file, ensure you include the following:
81
81
 
82
82
  ```ini
83
83
  # Add pyjnius so ensure it's packaged with the build
84
- requirements = python3, kivy, pyjnius, android-notify==1.60.8.dev0
84
+ requirements = python3, kivy, pyjnius, android-notify==1.60.9.dev0
85
85
  # Add permission for notifications
86
86
  android.permissions = POST_NOTIFICATIONS
87
87
  ```
@@ -99,7 +99,7 @@ In your `pyproject.toml` file, ensure you include the following:
99
99
  ```toml
100
100
  [tool.flet.android]
101
101
  dependencies = [
102
- "pyjnius","android-notify==1.60.8.dev0"
102
+ "pyjnius","android-notify==1.60.9.dev0"
103
103
  ]
104
104
 
105
105
  [tool.flet.android.permission]
@@ -117,10 +117,10 @@ dependencies = [
117
117
  <br/>
118
118
 
119
119
  On the [pydroid 3](https://play.google.com/store/apps/details?id=ru.iiec.pydroid3) mobile app for running python code you can test some features.
120
- - In pip section where you're asked to insert `Libary name` paste `android-notify==1.60.8.dev0`
120
+ - In pip section where you're asked to insert `Libary name` paste `android-notify==1.60.9.dev0`
121
121
  - Minimal working example
122
122
  ```py
123
- # Testing with `android-notify==1.60.8.dev0` on pydroid
123
+ # Testing with `android-notify==1.60.9.dev0` on pydroid
124
124
  from kivy.app import App
125
125
  from kivy.uix.boxlayout import BoxLayout
126
126
  from kivy.uix.button import Button
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "android-notify"
7
- version = "1.60.8.dev0"
7
+ version = "1.60.9.dev0"
8
8
  description = "A Python package that simplifies creating Android notifications in Kivy and Flet apps."
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  authors = [
@@ -1,61 +0,0 @@
1
- import logging
2
- import sys
3
- import os
4
-
5
- class KivyColorFormatter(logging.Formatter):
6
- COLORS = {
7
- 'DEBUG': '\x1b[1;36m', # bold cyan
8
- 'INFO': '\x1b[1;92m', # bold lime green
9
- 'WARNING': '\x1b[1;93m', # bold yellow
10
- 'ERROR': '\x1b[1;91m', # bold red
11
- 'CRITICAL': '\x1b[1;95m', # bold magenta
12
- }
13
- RESET = '\x1b[0m'
14
-
15
- def format(self, record):
16
- level = record.levelname.ljust(7)
17
- name = record.name.ljust(14)
18
- msg = record.getMessage()
19
-
20
- if getattr(sys.stdout, "isatty", lambda: False)():
21
- color = self.COLORS.get(record.levelname, '')
22
- level = f"{color}{level}{self.RESET}"
23
-
24
- return f"[{level}] [{name}] {msg}"
25
-
26
-
27
- logger = logging.getLogger("android_notify")
28
- # logger.setLevel(logging.NOTSET) # this override app logger level
29
-
30
- handler = logging.StreamHandler(sys.stdout)
31
- formatter = KivyColorFormatter()
32
- handler.setFormatter(formatter)
33
- # handler.setLevel(logging.WARNING) # this override app logger level
34
-
35
- # Avoid duplicate logs if root logger is configured
36
- logger.propagate = False
37
- # if not logger.handlers:
38
- logger.addHandler(handler)
39
- logger._configured = True
40
-
41
-
42
-
43
- env_level = os.getenv("ANDROID_NOTIFY_LOGLEVEL")
44
- if env_level:
45
- # noinspection PyBroadException
46
- try:
47
- logging.getLogger("android_notify").setLevel( getattr(logging, env_level.upper()) )
48
- except Exception as android_notify_loglevel_error:
49
- print("android_notify_loglevel_error:",android_notify_loglevel_error)
50
- pass
51
-
52
-
53
-
54
- if __name__ == "__main__":
55
- from kivymd.app import MDApp
56
-
57
- logger.debug("Debug message - should not appear with INFO level")
58
- logger.info("Info message")
59
- logger.warning("Warning message")
60
- logger.error("Error message")
61
- logger.critical("Critical message")