android-notify 1.60.7.dev0__tar.gz → 1.60.8__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 (54) hide show
  1. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/PKG-INFO +45 -28
  2. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/README.md +44 -27
  3. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/__init__.py +7 -2
  4. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/config.py +1 -2
  5. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/core.py +5 -4
  6. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/internal/facade.py +0 -6
  7. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/internal/helper.py +5 -3
  8. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/internal/java_classes.py +17 -10
  9. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/internal/permissions.py +47 -10
  10. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/main.py +28 -10
  11. android_notify-1.60.8/android_notify/tests/test_notification_permission.py +36 -0
  12. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/widgets/images.py +1 -4
  13. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/widgets/texts.py +2 -5
  14. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify.egg-info/PKG-INFO +45 -28
  15. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify.egg-info/SOURCES.txt +6 -7
  16. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/pyproject.toml +1 -1
  17. android_notify-1.60.7.dev0/docs/examples/flet-working/src/core.py +0 -221
  18. android_notify-1.60.7.dev0/docs/tests/flet/basic/src/core.py +0 -221
  19. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/__main__.py +0 -0
  20. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/base.py +0 -0
  21. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/fallback-icons/flet-appicon.png +0 -0
  22. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/fallback-icons/pydroid3-appicon.png +0 -0
  23. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/internal/an_types.py +0 -0
  24. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/internal/android.py +0 -0
  25. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/internal/channels.py +0 -0
  26. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/internal/intents.py +0 -0
  27. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/internal/logger.py +0 -0
  28. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/styles.py +0 -0
  29. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/sword.py +0 -0
  30. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/__init__.py +0 -0
  31. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/android_notify_test.py +0 -0
  32. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/base_test.py +0 -0
  33. {android_notify-1.60.7.dev0/docs → android_notify-1.60.8/android_notify}/tests/flet/adv/main.py +0 -0
  34. {android_notify-1.60.7.dev0/docs → android_notify-1.60.8/android_notify}/tests/flet/adv/tests/__init__.py +0 -0
  35. {android_notify-1.60.7.dev0/docs → android_notify-1.60.8/android_notify}/tests/flet/adv/tests/test_android_notify_full.py +0 -0
  36. {android_notify-1.60.7.dev0/docs → android_notify-1.60.8/android_notify}/tests/flet/basic/src/main.py +0 -0
  37. {android_notify-1.60.7.dev0/docs/examples → android_notify-1.60.8/android_notify/tests/flet}/flet-working/src/main.py +0 -0
  38. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/p4a/hook.py +0 -0
  39. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/serivces/wallpaper.py +0 -0
  40. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/test_basic_notifications.py +0 -0
  41. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/test_notification_actions.py +0 -0
  42. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/test_notification_appearance.py +0 -0
  43. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/test_notification_behavior.py +0 -0
  44. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/test_notification_channels.py +0 -0
  45. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/test_notification_clear.py +0 -0
  46. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/test_notification_progress.py +0 -0
  47. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/test_notification_sound.py +0 -0
  48. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify/tests/test_notification_styles.py +0 -0
  49. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify.egg-info/dependency_links.txt +0 -0
  50. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify.egg-info/entry_points.txt +0 -0
  51. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify.egg-info/requires.txt +0 -0
  52. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/android_notify.egg-info/top_level.txt +0 -0
  53. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/docs/website/src/pages/data/laner_Sent.py +0 -0
  54. {android_notify-1.60.7.dev0 → android_notify-1.60.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: android-notify
3
- Version: 1.60.7.dev0
3
+ Version: 1.60.8
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,9 +81,14 @@ 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.7.dev0
84
+ requirements = python3, kivy, pyjnius, android-notify
85
85
  # Add permission for notifications
86
86
  android.permissions = POST_NOTIFICATIONS
87
+
88
+ # Required dependencies (write exactly as shown, no quotation marks)
89
+ android.gradle_dependencies = androidx.core:core:1.6.0, androidx.core:core-ktx:1.15.0
90
+ android.enable_androidx = True
91
+ android.api = 35
87
92
  ```
88
93
 
89
94
  </details>
@@ -93,13 +98,13 @@ android.permissions = POST_NOTIFICATIONS
93
98
  <summary><b>Flet apps:</b></summary>
94
99
  <br/>
95
100
 
96
- In your `pyproject.toml` file, ensure you include the following:
101
+ In your `pyproject.toml` file, ensure you include the following:
97
102
 
98
103
 
99
104
  ```toml
100
105
  [tool.flet.android]
101
106
  dependencies = [
102
- "pyjnius","android-notify==1.60.7.dev0"
107
+ "pyjnius","android-notify==1.60.8.dev0"
103
108
  ]
104
109
 
105
110
  [tool.flet.android.permission]
@@ -109,7 +114,35 @@ dependencies = [
109
114
 
110
115
  </details>
111
116
 
117
+ <details>
118
+
119
+ <summary><b>Desktop</b></summary>
120
+ <br/>
121
+
122
+ For IDE IntelliSense Can be installed via `pip install`:
123
+
124
+ ```bash
125
+ pip install android_notify
126
+ android-notify -v
127
+ ```
128
+
129
+ </details>
130
+
131
+ ------
132
+ ## Installing without Androidx
133
+ How to use without `gradle_dependencies`
134
+ Use `android-notify==1.60.8.dev0` to install via `pip`
135
+
136
+ <details>
137
+ <summary><b>In Kivy</b></summary>
138
+ <br/>
139
+
140
+ ```ini
141
+ # buildozer.spec
142
+ requirements = python3, kivy, pyjnius, android-notify==1.60.8.dev0
143
+ ```
112
144
 
145
+ </details>
113
146
 
114
147
  <details>
115
148
 
@@ -117,10 +150,10 @@ dependencies = [
117
150
  <br/>
118
151
 
119
152
  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.7.dev0`
153
+ - In pip section where you're asked to insert `Libary name` paste `android-notify==1.60.8.dev0`
121
154
  - Minimal working example
122
155
  ```py
123
- # Testing with `android-notify==1.60.7.dev0` on pydroid
156
+ # Testing with `android-notify==1.60.8.dev0` on pydroid
124
157
  from kivy.app import App
125
158
  from kivy.uix.boxlayout import BoxLayout
126
159
  from kivy.uix.button import Button
@@ -160,23 +193,11 @@ if __name__ == "__main__":
160
193
  </details>
161
194
 
162
195
 
163
- <details>
164
-
165
- <summary><b>Desktop</b></summary>
166
- <br/>
167
-
168
- For IDE IntelliSense Can be installed via `pip install`:
169
-
170
- ```bash
171
- pip install android_notify
172
- android-notify -v
173
- ```
174
- </details>
175
196
 
176
197
  ## Documentation
177
- For Dev Version use
198
+ For Dev Version usage
178
199
  ```ini
179
- requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/without-androidx.zip
200
+ requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/main.zip
180
201
  ```
181
202
 
182
203
  <details>
@@ -185,7 +206,7 @@ requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_noti
185
206
  - Make things happen without being in your app
186
207
  ```python
187
208
  from android_notify import Notification
188
- notification = Notification(title="Receiver Notification")
209
+ notification = Notification(title="Reciver Notification")
189
210
  notification.addButton(text="Stop", receiver_name="CarouselReceiver", action="ACTION_STOP")
190
211
  notification.addButton(text="Skip", receiver_name="CarouselReceiver", action="ACTION_SKIP")
191
212
  ```
@@ -248,7 +269,7 @@ Notification.createChannel(id='shake', name="Shake Passage", vibrate=True)
248
269
 
249
270
  n=Notification(title='Vibrate',channel_id='shake')
250
271
  n.setVibrate() # for less than android 8
251
- n.fVibrate() # To Force Vibrate (when user turned off in settings)
272
+ n.fVibrate() # To Force Vibrate
252
273
  n.send()
253
274
  ```
254
275
 
@@ -286,9 +307,5 @@ from android_notify import Notification, NotificationHandler
286
307
 
287
308
  ## ☕ Support the Project
288
309
 
289
- If you find this project helpful, consider buying me a coffee! 😊
290
- Or Giving it a star on 🌟 [GitHub](https://github.com/Fector101/android_notify/) Your support helps maintain and improve the project.
291
-
292
- <a href="https://www.buymeacoffee.com/fector101" target="_blank">
293
- <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="60">
294
- </a>
310
+ If you find this project helpful, your support would help me continue working on open-source projects
311
+ [donate](https://www.buymeacoffee.com/fector101)
@@ -58,9 +58,14 @@ 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.7.dev0
61
+ requirements = python3, kivy, pyjnius, android-notify
62
62
  # Add permission for notifications
63
63
  android.permissions = POST_NOTIFICATIONS
64
+
65
+ # Required dependencies (write exactly as shown, no quotation marks)
66
+ android.gradle_dependencies = androidx.core:core:1.6.0, androidx.core:core-ktx:1.15.0
67
+ android.enable_androidx = True
68
+ android.api = 35
64
69
  ```
65
70
 
66
71
  </details>
@@ -70,13 +75,13 @@ android.permissions = POST_NOTIFICATIONS
70
75
  <summary><b>Flet apps:</b></summary>
71
76
  <br/>
72
77
 
73
- In your `pyproject.toml` file, ensure you include the following:
78
+ In your `pyproject.toml` file, ensure you include the following:
74
79
 
75
80
 
76
81
  ```toml
77
82
  [tool.flet.android]
78
83
  dependencies = [
79
- "pyjnius","android-notify==1.60.7.dev0"
84
+ "pyjnius","android-notify==1.60.8.dev0"
80
85
  ]
81
86
 
82
87
  [tool.flet.android.permission]
@@ -86,7 +91,35 @@ dependencies = [
86
91
 
87
92
  </details>
88
93
 
94
+ <details>
95
+
96
+ <summary><b>Desktop</b></summary>
97
+ <br/>
98
+
99
+ For IDE IntelliSense Can be installed via `pip install`:
100
+
101
+ ```bash
102
+ pip install android_notify
103
+ android-notify -v
104
+ ```
105
+
106
+ </details>
107
+
108
+ ------
109
+ ## Installing without Androidx
110
+ How to use without `gradle_dependencies`
111
+ Use `android-notify==1.60.8.dev0` to install via `pip`
112
+
113
+ <details>
114
+ <summary><b>In Kivy</b></summary>
115
+ <br/>
116
+
117
+ ```ini
118
+ # buildozer.spec
119
+ requirements = python3, kivy, pyjnius, android-notify==1.60.8.dev0
120
+ ```
89
121
 
122
+ </details>
90
123
 
91
124
  <details>
92
125
 
@@ -94,10 +127,10 @@ dependencies = [
94
127
  <br/>
95
128
 
96
129
  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.7.dev0`
130
+ - In pip section where you're asked to insert `Libary name` paste `android-notify==1.60.8.dev0`
98
131
  - Minimal working example
99
132
  ```py
100
- # Testing with `android-notify==1.60.7.dev0` on pydroid
133
+ # Testing with `android-notify==1.60.8.dev0` on pydroid
101
134
  from kivy.app import App
102
135
  from kivy.uix.boxlayout import BoxLayout
103
136
  from kivy.uix.button import Button
@@ -137,23 +170,11 @@ if __name__ == "__main__":
137
170
  </details>
138
171
 
139
172
 
140
- <details>
141
-
142
- <summary><b>Desktop</b></summary>
143
- <br/>
144
-
145
- For IDE IntelliSense Can be installed via `pip install`:
146
-
147
- ```bash
148
- pip install android_notify
149
- android-notify -v
150
- ```
151
- </details>
152
173
 
153
174
  ## Documentation
154
- For Dev Version use
175
+ For Dev Version usage
155
176
  ```ini
156
- requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/without-androidx.zip
177
+ requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/main.zip
157
178
  ```
158
179
 
159
180
  <details>
@@ -162,7 +183,7 @@ requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_noti
162
183
  - Make things happen without being in your app
163
184
  ```python
164
185
  from android_notify import Notification
165
- notification = Notification(title="Receiver Notification")
186
+ notification = Notification(title="Reciver Notification")
166
187
  notification.addButton(text="Stop", receiver_name="CarouselReceiver", action="ACTION_STOP")
167
188
  notification.addButton(text="Skip", receiver_name="CarouselReceiver", action="ACTION_SKIP")
168
189
  ```
@@ -225,7 +246,7 @@ Notification.createChannel(id='shake', name="Shake Passage", vibrate=True)
225
246
 
226
247
  n=Notification(title='Vibrate',channel_id='shake')
227
248
  n.setVibrate() # for less than android 8
228
- n.fVibrate() # To Force Vibrate (when user turned off in settings)
249
+ n.fVibrate() # To Force Vibrate
229
250
  n.send()
230
251
  ```
231
252
 
@@ -263,9 +284,5 @@ from android_notify import Notification, NotificationHandler
263
284
 
264
285
  ## ☕ Support the Project
265
286
 
266
- If you find this project helpful, consider buying me a coffee! 😊
267
- Or Giving it a star on 🌟 [GitHub](https://github.com/Fector101/android_notify/) Your support helps maintain and improve the project.
268
-
269
- <a href="https://www.buymeacoffee.com/fector101" target="_blank">
270
- <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="60">
271
- </a>
287
+ If you find this project helpful, your support would help me continue working on open-source projects
288
+ [donate](https://www.buymeacoffee.com/fector101)
@@ -1,5 +1,10 @@
1
- """"
2
- For Easier Imports For Public Classes
1
+ """
2
+ Android-Notify
3
+ =================
4
+
5
+ For Creating Android Notifications In Python Apps.
6
+
7
+ All the documentation is available at: https://android-notify.vercel.app/
3
8
  """
4
9
  from .core import send_notification
5
10
  from .styles import NotificationStyles
@@ -1,7 +1,6 @@
1
1
  import os
2
2
 
3
- __version__ = "1.60.7.dev0"
4
-
3
+ __version__ = "1.60.8"
5
4
 
6
5
  from .internal.java_classes import autoclass, cast, NotificationManager
7
6
  from .internal.logger import logger
@@ -6,7 +6,7 @@ from android_notify.internal.logger import logger
6
6
  from android_notify.config import get_python_activity, on_android_platform, get_python_activity_context
7
7
  from android_notify.internal.permissions import has_notification_permission, ask_notification_permission
8
8
  from android_notify.internal.java_classes import autoclass, BuildVersion, BitmapFactory, NotificationChannel, NotificationManagerCompat, NotificationCompat, NotificationCompatBuilder, \
9
- NotificationCompatBigTextStyle, NotificationCompatBigPictureStyle, NotificationCompatInboxStyle
9
+ NotificationCompatBigTextStyle, NotificationCompatBigPictureStyle, NotificationCompatInboxStyle, IconCompat
10
10
 
11
11
 
12
12
 
@@ -49,7 +49,7 @@ def get_image_uri(relative_path):
49
49
  """
50
50
  app_root_path = get_app_root_path()
51
51
  output_path = os.path.join(app_root_path, relative_path)
52
- # drint(output_path,'output_path') # /data/user/0/org.laner.lan_ft/files/app/assets/imgs/icon.png
52
+ # rint(output_path,'output_path') # /data/user/0/org.laner.lan_ft/files/app/assets/imgs/icon.png
53
53
 
54
54
  if not os.path.exists(output_path):
55
55
  raise FileNotFoundError(f"\nImage not found at path: {output_path}\n")
@@ -60,7 +60,6 @@ def get_image_uri(relative_path):
60
60
 
61
61
  def get_icon_object(uri):
62
62
  context = get_python_activity_context()
63
- IconCompat = autoclass('android.graphics.drawable.Icon')
64
63
  bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri))
65
64
  return IconCompat.createWithBitmap(bitmap)
66
65
 
@@ -115,7 +114,9 @@ def send_notification(
115
114
  return None
116
115
  context = get_python_activity_context()
117
116
 
118
- asks_permission_if_needed(legacy=True)
117
+
118
+ asks_permission_if_needed()
119
+
119
120
  channel_id = channel_name.replace(' ', '_').lower().lower() if not channel_id else channel_id
120
121
  # Get notification manager
121
122
  notification_manager = context.getSystemService(context.NOTIFICATION_SERVICE)
@@ -175,12 +175,6 @@ class NotificationManagerCompat:
175
175
  IMPORTANCE_MIN = ''
176
176
  IMPORTANCE_NONE = ''
177
177
 
178
- class AndroidNotification:
179
- DEFAULT_ALL = 3
180
- PRIORITY_HIGH = 4
181
- PRIORITY_DEFAULT = ''
182
- PRIORITY_LOW = ''
183
- PRIORITY_MIN = ''
184
178
 
185
179
  class NotificationCompat:
186
180
  DEFAULT_ALL = 3
@@ -40,14 +40,16 @@ def get_package_path():
40
40
  return os.path.dirname(os.path.abspath(__file__))
41
41
 
42
42
 
43
- def execute_callback(callback,arg):
43
+ def execute_callback(callback,arg, from_who="user"):
44
44
  """
45
45
  Executing Callbacks Safely
46
46
  """
47
- if callback:
47
+ if not callback:
48
48
  return None
49
+ if from_who == "user":
50
+ logger.info(f"Executing On Permission Result Callback...")
49
51
  try:
50
- if can_accept_arguments(callback, True):
52
+ if can_accept_arguments(callback, arg):
51
53
  callback(arg)
52
54
  else:
53
55
  callback()
@@ -39,24 +39,31 @@ if on_android_platform():
39
39
  Manifest = autoclass('android.Manifest$permission')
40
40
  Color = autoclass('android.graphics.Color')
41
41
  Context = autoclass('android.content.Context')
42
- PackageManager = autoclass("android.content.pm.PackageManager")
43
42
  except Exception as e:
44
43
  from .facade import *
45
44
  logger.exception("Didn't get Basic Java Classes")
46
45
 
47
46
  # noinspection PyBroadException
48
47
  try:
49
- NotificationManagerCompat = NotificationManager # I need other files identical to main branch so it's easier to maintain
50
- NotificationCompat = autoclass("android.app.Notification")
51
- NotificationCompatBuilder = autoclass('android.app.Notification$Builder')
52
- NotificationCompatBigTextStyle = autoclass('android.app.Notification$BigTextStyle')
53
- NotificationCompatBigPictureStyle = autoclass('android.app.Notification$BigPictureStyle')
54
- NotificationCompatInboxStyle = autoclass('android.app.Notification$InboxStyle')
48
+ NotificationManagerCompat = autoclass('androidx.core.app.NotificationManagerCompat')
49
+ NotificationCompat = autoclass('androidx.core.app.NotificationCompat')
50
+ NotificationCompatBuilder = autoclass('androidx.core.app.NotificationCompat$Builder')
51
+ IconCompat = autoclass('androidx.core.graphics.drawable.IconCompat')
55
52
 
56
- except Exception as styles_import_error:
57
- logger.exception(styles_import_error)
58
- from .facade import *
53
+ # Notification Design
54
+ NotificationCompatBigTextStyle = autoclass('androidx.core.app.NotificationCompat$BigTextStyle')
55
+ NotificationCompatBigPictureStyle = autoclass('androidx.core.app.NotificationCompat$BigPictureStyle')
56
+ NotificationCompatInboxStyle = autoclass('androidx.core.app.NotificationCompat$InboxStyle')
57
+ NotificationCompatDecoratedCustomViewStyle = autoclass('androidx.core.app.NotificationCompat$DecoratedCustomViewStyle')
58
+
59
+ except Exception as dependencies_import_error:
60
+ logger.exception("""
61
+ Dependency Error: Add the following in buildozer.spec:
62
+ * android.gradle_dependencies = androidx.core:core-ktx:1.15.0, androidx.core:core:1.6.0
63
+ * android.enable_androidx = True
64
+ """)
59
65
 
66
+ from .facade import *
60
67
  else:
61
68
  cast = lambda x, y: x
62
69
  autoclass = lambda x: None
@@ -1,10 +1,11 @@
1
1
  """
2
2
  For Permission Related Blocks
3
3
  """
4
+ import os.path
4
5
 
5
6
  from .logger import logger
6
7
  from android_notify.config import on_android_platform, on_flet_app, get_python_activity_context
7
- 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
8
9
  from android_notify.internal.helper import execute_callback
9
10
 
10
11
 
@@ -22,8 +23,10 @@ def has_notification_permission():
22
23
  if on_flet_app():
23
24
  context = get_python_activity_context()
24
25
  permission = Manifest.POST_NOTIFICATIONS
25
-
26
- return PackageManager.PERMISSION_GRANTED == context.checkSelfPermission(permission)
26
+ ContextCompat = autoclass('androidx.core.content.ContextCompat')
27
+ # if you get error `Failed to find class: androidx/core/app/ActivityCompat`
28
+ # in proguard-rules.pro add `-keep class androidx.core.app.ActivityCompat { *; }`
29
+ return ContextCompat.checkSelfPermission(context, permission)
27
30
  else:
28
31
  from android.permissions import Permission, check_permission # type: ignore
29
32
  return check_permission(Permission.POST_NOTIFICATIONS)
@@ -45,10 +48,16 @@ def ask_notification_permission(callback=None, set_requesting_state=None, legacy
45
48
  logger.warning("Already have permission to send notifications")
46
49
  return None
47
50
 
48
- if not can_show_permission_request_popup():
51
+ if not is_first_permission_ask() and not can_show_permission_request_popup():
49
52
  logger.warning("""Permission to send notifications has been denied permanently.
50
- This happens when the user denies permission twice from the popup.
51
- Opening notification settings...""")
53
+ This can happen when the user denies permission twice from the popup.
54
+
55
+ Opening notification settings...
56
+
57
+ Add in MDApp().on_resume():
58
+ >> if NotificationHandler.has_permission() and self.screen_manager:
59
+ >> self.screen_manager.current = "home_screen"
60
+ """)
52
61
  open_notification_settings_screen()
53
62
  return None
54
63
 
@@ -57,21 +66,38 @@ def ask_notification_permission(callback=None, set_requesting_state=None, legacy
57
66
  def on_permissions_result(_, grants):
58
67
  # _ is permissions
59
68
  execute_callback(callback, grants[0])
60
- execute_callback(set_requesting_state, False)
69
+ execute_callback(set_requesting_state, False,from_who="package")
61
70
 
62
- if legacy or on_flet_app():
71
+ if legacy:
63
72
  # TODO Handle activity with request code
73
+ PackageManager = autoclass("android.content.pm.PackageManager")
64
74
  permission = Manifest.POST_NOTIFICATIONS
65
- context.requestPermissions([permission], 101)
75
+
76
+ granted = context.checkSelfPermission(permission)
77
+ if granted != PackageManager.PERMISSION_GRANTED:
78
+ context.requestPermissions([permission], 101)
79
+ return None
80
+ elif on_flet_app():
81
+ # TODO Callback when user answers request question
82
+ # Can't bind activity result method is from p4a which is only on kivy
83
+ ActivityCompat = autoclass('androidx.core.app.ActivityCompat')
84
+ permission = Manifest.POST_NOTIFICATIONS
85
+ ActivityCompat.requestPermissions(context, [permission], 101)
66
86
  return None
67
87
  else:
68
88
  from android.permissions import request_permissions, Permission # type: ignore
69
- execute_callback(set_requesting_state, True)
89
+ execute_callback(set_requesting_state, True,from_who="package")
70
90
  request_permissions([Permission.POST_NOTIFICATIONS], on_permissions_result)
71
91
  return None
72
92
 
73
93
 
74
94
  def open_notification_settings_screen():
95
+ """In MDApp().on_resume()
96
+
97
+ Example:
98
+ >>> if NotificationHandler.has_permission() and self.screen_manager:
99
+ >>> self.screen_manager.current = "home_screen"
100
+ """
75
101
  context = get_python_activity_context()
76
102
 
77
103
  if not context:
@@ -114,3 +140,14 @@ def can_show_permission_request_popup():
114
140
  return False
115
141
 
116
142
  return context.shouldShowRequestPermissionRationale(Manifest.POST_NOTIFICATIONS)
143
+
144
+
145
+ def is_first_permission_ask():
146
+ from importlib.resources import files
147
+ buffer_file_name = "ASKED_PERMISSION.txt"
148
+ absolute_buffer_file_path = str(files("android_notify") / buffer_file_name) # Making sure one path is always used
149
+
150
+ if os.path.exists(absolute_buffer_file_path):
151
+ return False
152
+ open(absolute_buffer_file_path,'w').close()
153
+ return True
@@ -29,6 +29,7 @@ from android_notify.tests.test_notification_behavior import TestNotificationBeha
29
29
  from android_notify.tests.test_notification_progress import TestNotificationProgress
30
30
  from android_notify.tests.test_notification_sound import TestNotificationSound
31
31
  from android_notify.tests.test_notification_clear import TestClearNotifications
32
+ from android_notify.tests.test_notification_permission import NOTIFICATION_PERMISSION_TESTS
32
33
  from kivy.clock import Clock
33
34
 
34
35
  # -----------------------------
@@ -82,6 +83,7 @@ class TripleClickButton(Button):
82
83
  class AndroidNotifyDemoApp(MDApp):
83
84
 
84
85
  def on_start(self):
86
+ print('starting app...')
85
87
  try:
86
88
  from kivymd.toast import toast
87
89
  name = NotificationHandler.get_name(on_start=True)
@@ -89,6 +91,7 @@ class AndroidNotifyDemoApp(MDApp):
89
91
  except Exception as e:
90
92
  print("Error getting notify name:", e)
91
93
 
94
+ print('on_start','-'*33)
92
95
 
93
96
  def android_service():
94
97
 
@@ -154,11 +157,28 @@ class AndroidNotifyDemoApp(MDApp):
154
157
  self.test_buttons.append(btn)
155
158
  main.add_widget(btn)
156
159
 
160
+ # Permission request needs human inputs for tests
161
+ for label, action in NOTIFICATION_PERMISSION_TESTS.items():
162
+ btn = self._btn(
163
+ f"Run: {label}",
164
+ lambda _, fn=action: self.run_action(fn, _)
165
+ )
166
+ main.add_widget(btn)
157
167
  return root
158
168
 
159
- # -----------------------------
160
- # Helper to make buttons
161
- # -----------------------------
169
+ def run_action(self, action_fn, btn_instance):
170
+ btn_instance.disabled = True
171
+ print(f"\n▶ Running action: {action_fn.__name__}")
172
+
173
+ try:
174
+ action_fn()
175
+ except Exception as error_running_action:
176
+ print("error_running_action:", error_running_action)
177
+ traceback.print_exc()
178
+ finally:
179
+ # Re-enable AFTER user interaction finishes
180
+ btn_instance.disabled = False
181
+
162
182
  def _btn(self, text, callback, height=80):
163
183
  return TripleClickButton(
164
184
  text=text,
@@ -185,9 +205,6 @@ class AndroidNotifyDemoApp(MDApp):
185
205
  for btn in self.test_buttons:
186
206
  btn.disabled = False
187
207
 
188
- # -----------------------------
189
- # Actions
190
- # -----------------------------
191
208
  def request_permission(self, btn_instance):
192
209
  asks_permission_if_needed()
193
210
  btn_instance.disabled = False
@@ -204,16 +221,17 @@ class AndroidNotifyDemoApp(MDApp):
204
221
  btn_instance.disabled = False
205
222
 
206
223
  def on_resume(self):
224
+ print('resuming app..')
207
225
  try:
208
226
  from kivymd.toast import toast
209
227
  name = NotificationHandler.get_name()
210
- toast(text=f"name: {name}", length_long=True)
228
+
229
+ toast(text=f"name: {name}, Permission:{NotificationHandler.has_permission()}", length_long=True)
211
230
  except Exception as e:
212
231
  print("Error getting notify name:", e)
232
+ print('on_resume','-'*33)
233
+
213
234
 
214
235
 
215
- # -----------------------------
216
- # Entry
217
- # -----------------------------
218
236
  if __name__ == "__main__":
219
237
  AndroidNotifyDemoApp().run()
@@ -0,0 +1,36 @@
1
+ from android_notify import NotificationHandler
2
+ from android_notify.internal.permissions import ask_notification_permission
3
+ from android_notify.core import asks_permission_if_needed
4
+
5
+
6
+ def ask_permission_no_callback():
7
+ NotificationHandler.asks_permission()
8
+
9
+
10
+ def ask_permission_with_callback():
11
+ def some_callback(answer):
12
+ print(f"Hey Dude, Notification Request result {answer}.")
13
+ NotificationHandler.asks_permission(some_callback)
14
+
15
+
16
+ def ask_permission_simple_regular():
17
+ asks_permission_if_needed()
18
+
19
+
20
+ def ask_permission_simple_legacy():
21
+ asks_permission_if_needed(legacy=True)
22
+
23
+
24
+ def ask_permission_from_source():
25
+ def some_callback(answer):
26
+ print(f"Hey, Notification Request Request1: {answer}")
27
+ ask_notification_permission(callback=some_callback)
28
+
29
+
30
+ NOTIFICATION_PERMISSION_TESTS = {
31
+ "permission (no callback)": ask_permission_no_callback,
32
+ "permission (with callback)": ask_permission_with_callback,
33
+ "permission (simple)": ask_permission_simple_regular,
34
+ "permission (legacy)": ask_permission_simple_legacy,
35
+ "permission (from source)": ask_permission_from_source,
36
+ }
@@ -4,7 +4,7 @@ For image related things
4
4
  import os
5
5
 
6
6
  from android_notify.config import app_storage_path, on_flet_app, on_android_platform, get_python_activity_context
7
- from android_notify.internal.java_classes import autoclass, BitmapFactory, Uri, BuildVersion, Color
7
+ from android_notify.internal.java_classes import autoclass, BitmapFactory, Uri, BuildVersion, Color, IconCompat
8
8
  from android_notify.internal.helper import get_package_path
9
9
  from android_notify.internal.logger import logger
10
10
 
@@ -75,8 +75,6 @@ def icon_finder(icon_name):
75
75
  # noinspection PyPackageRequirements
76
76
  from importlib.resources import files
77
77
  return str(files("android_notify")/"fallback-icons"/icon_name)
78
- # import pkg_resources
79
- # return pkg_resources.resource_filename(__name__, f"fallback-icons/{icon_name}")
80
78
  except Exception:
81
79
  # Fallback if pkg_resources not available
82
80
  package_dir = get_package_path()
@@ -130,7 +128,6 @@ def set_small_icon_with_bitmap(bitmap, builder):
130
128
  logger.warning("Bitmap Insert as Icon Not available below Android 6")
131
129
  return False
132
130
  try:
133
- IconCompat = autoclass('android.graphics.drawable.Icon')
134
131
  icon = IconCompat.createWithBitmap(bitmap)
135
132
  builder.setSmallIcon(icon)
136
133
  return True