android-notify 1.60.10__tar.gz → 1.60.10.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.
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/PKG-INFO +25 -42
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/README.md +24 -41
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/config.py +2 -1
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/core.py +3 -4
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/internal/java_classes.py +10 -17
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/internal/permissions.py +8 -21
- android_notify-1.60.10.dev0/android_notify/tests/flet/basic/src/core.py +221 -0
- android_notify-1.60.10.dev0/android_notify/tests/flet/flet-working/src/core.py +221 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/widgets/images.py +2 -1
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/widgets/texts.py +5 -1
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify.egg-info/PKG-INFO +25 -42
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify.egg-info/SOURCES.txt +2 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/pyproject.toml +1 -1
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/__init__.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/__main__.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/base.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/fallback-icons/flet-appicon.png +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/fallback-icons/pydroid3-appicon.png +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/internal/an_types.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/internal/android.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/internal/channels.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/internal/facade.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/internal/helper.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/internal/intents.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/internal/logger.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/styles.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/sword.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/__init__.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/android_notify_test.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/base_test.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/flet/adv/main.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/flet/adv/tests/__init__.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/flet/adv/tests/test_android_notify_full.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/flet/basic/src/main.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/flet/flet-working/src/main.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/main.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/p4a/hook.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/serivces/wallpaper.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/test_basic_notifications.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/test_notification_actions.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/test_notification_appearance.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/test_notification_behavior.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/test_notification_channels.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/test_notification_clear.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/test_notification_permission.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/test_notification_progress.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/test_notification_sound.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/test_notification_styles.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify.egg-info/dependency_links.txt +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify.egg-info/entry_points.txt +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify.egg-info/requires.txt +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify.egg-info/top_level.txt +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/docs/website/src/pages/data/laner_Sent.py +0 -0
- {android_notify-1.60.10 → android_notify-1.60.10.dev0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: android-notify
|
|
3
|
-
Version: 1.60.10
|
|
3
|
+
Version: 1.60.10.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,14 +81,9 @@ 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
|
|
84
|
+
requirements = python3, kivy, pyjnius, android-notify==1.60.10.dev0
|
|
85
85
|
# Add permission for notifications
|
|
86
86
|
android.permissions = POST_NOTIFICATIONS
|
|
87
|
-
|
|
88
|
-
# Required dependency (write exactly as shown, no quotation marks)
|
|
89
|
-
android.gradle_dependencies = androidx.core:core-ktx:1.15.0
|
|
90
|
-
android.enable_androidx = True
|
|
91
|
-
android.api = 35
|
|
92
87
|
```
|
|
93
88
|
|
|
94
89
|
</details>
|
|
@@ -98,7 +93,7 @@ android.api = 35
|
|
|
98
93
|
<summary><b>Flet apps:</b></summary>
|
|
99
94
|
<br/>
|
|
100
95
|
|
|
101
|
-
|
|
96
|
+
In your `pyproject.toml` file, ensure you include the following:
|
|
102
97
|
|
|
103
98
|
|
|
104
99
|
```toml
|
|
@@ -114,35 +109,7 @@ dependencies = [
|
|
|
114
109
|
|
|
115
110
|
</details>
|
|
116
111
|
|
|
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.10.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.10.dev0
|
|
143
|
-
```
|
|
144
112
|
|
|
145
|
-
</details>
|
|
146
113
|
|
|
147
114
|
<details>
|
|
148
115
|
|
|
@@ -193,11 +160,23 @@ if __name__ == "__main__":
|
|
|
193
160
|
</details>
|
|
194
161
|
|
|
195
162
|
|
|
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>
|
|
196
175
|
|
|
197
176
|
## Documentation
|
|
198
|
-
For Dev Version
|
|
177
|
+
For Dev Version use
|
|
199
178
|
```ini
|
|
200
|
-
requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/
|
|
179
|
+
requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/without-androidx.zip
|
|
201
180
|
```
|
|
202
181
|
|
|
203
182
|
<details>
|
|
@@ -206,7 +185,7 @@ requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_noti
|
|
|
206
185
|
- Make things happen without being in your app
|
|
207
186
|
```python
|
|
208
187
|
from android_notify import Notification
|
|
209
|
-
notification = Notification(title="
|
|
188
|
+
notification = Notification(title="Receiver Notification")
|
|
210
189
|
notification.addButton(text="Stop", receiver_name="CarouselReceiver", action="ACTION_STOP")
|
|
211
190
|
notification.addButton(text="Skip", receiver_name="CarouselReceiver", action="ACTION_SKIP")
|
|
212
191
|
```
|
|
@@ -269,7 +248,7 @@ Notification.createChannel(id='shake', name="Shake Passage", vibrate=True)
|
|
|
269
248
|
|
|
270
249
|
n=Notification(title='Vibrate',channel_id='shake')
|
|
271
250
|
n.setVibrate() # for less than android 8
|
|
272
|
-
n.fVibrate() # To Force Vibrate
|
|
251
|
+
n.fVibrate() # To Force Vibrate (when user turned off in settings)
|
|
273
252
|
n.send()
|
|
274
253
|
```
|
|
275
254
|
|
|
@@ -307,5 +286,9 @@ from android_notify import Notification, NotificationHandler
|
|
|
307
286
|
|
|
308
287
|
## ☕ Support the Project
|
|
309
288
|
|
|
310
|
-
If you find this project helpful,
|
|
311
|
-
[
|
|
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>
|
|
@@ -58,14 +58,9 @@ 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
|
|
61
|
+
requirements = python3, kivy, pyjnius, android-notify==1.60.10.dev0
|
|
62
62
|
# Add permission for notifications
|
|
63
63
|
android.permissions = POST_NOTIFICATIONS
|
|
64
|
-
|
|
65
|
-
# Required dependency (write exactly as shown, no quotation marks)
|
|
66
|
-
android.gradle_dependencies = androidx.core:core-ktx:1.15.0
|
|
67
|
-
android.enable_androidx = True
|
|
68
|
-
android.api = 35
|
|
69
64
|
```
|
|
70
65
|
|
|
71
66
|
</details>
|
|
@@ -75,7 +70,7 @@ android.api = 35
|
|
|
75
70
|
<summary><b>Flet apps:</b></summary>
|
|
76
71
|
<br/>
|
|
77
72
|
|
|
78
|
-
|
|
73
|
+
In your `pyproject.toml` file, ensure you include the following:
|
|
79
74
|
|
|
80
75
|
|
|
81
76
|
```toml
|
|
@@ -91,35 +86,7 @@ dependencies = [
|
|
|
91
86
|
|
|
92
87
|
</details>
|
|
93
88
|
|
|
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.10.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.10.dev0
|
|
120
|
-
```
|
|
121
89
|
|
|
122
|
-
</details>
|
|
123
90
|
|
|
124
91
|
<details>
|
|
125
92
|
|
|
@@ -170,11 +137,23 @@ if __name__ == "__main__":
|
|
|
170
137
|
</details>
|
|
171
138
|
|
|
172
139
|
|
|
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>
|
|
173
152
|
|
|
174
153
|
## Documentation
|
|
175
|
-
For Dev Version
|
|
154
|
+
For Dev Version use
|
|
176
155
|
```ini
|
|
177
|
-
requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/
|
|
156
|
+
requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/without-androidx.zip
|
|
178
157
|
```
|
|
179
158
|
|
|
180
159
|
<details>
|
|
@@ -183,7 +162,7 @@ requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_noti
|
|
|
183
162
|
- Make things happen without being in your app
|
|
184
163
|
```python
|
|
185
164
|
from android_notify import Notification
|
|
186
|
-
notification = Notification(title="
|
|
165
|
+
notification = Notification(title="Receiver Notification")
|
|
187
166
|
notification.addButton(text="Stop", receiver_name="CarouselReceiver", action="ACTION_STOP")
|
|
188
167
|
notification.addButton(text="Skip", receiver_name="CarouselReceiver", action="ACTION_SKIP")
|
|
189
168
|
```
|
|
@@ -246,7 +225,7 @@ Notification.createChannel(id='shake', name="Shake Passage", vibrate=True)
|
|
|
246
225
|
|
|
247
226
|
n=Notification(title='Vibrate',channel_id='shake')
|
|
248
227
|
n.setVibrate() # for less than android 8
|
|
249
|
-
n.fVibrate() # To Force Vibrate
|
|
228
|
+
n.fVibrate() # To Force Vibrate (when user turned off in settings)
|
|
250
229
|
n.send()
|
|
251
230
|
```
|
|
252
231
|
|
|
@@ -284,5 +263,9 @@ from android_notify import Notification, NotificationHandler
|
|
|
284
263
|
|
|
285
264
|
## ☕ Support the Project
|
|
286
265
|
|
|
287
|
-
If you find this project helpful,
|
|
288
|
-
[
|
|
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>
|
|
@@ -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
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
@@ -60,6 +60,7 @@ 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')
|
|
63
64
|
bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri))
|
|
64
65
|
return IconCompat.createWithBitmap(bitmap)
|
|
65
66
|
|
|
@@ -114,9 +115,7 @@ def send_notification(
|
|
|
114
115
|
return None
|
|
115
116
|
context = get_python_activity_context()
|
|
116
117
|
|
|
117
|
-
|
|
118
|
-
asks_permission_if_needed()
|
|
119
|
-
|
|
118
|
+
asks_permission_if_needed(legacy=True)
|
|
120
119
|
channel_id = channel_name.replace(' ', '_').lower().lower() if not channel_id else channel_id
|
|
121
120
|
# Get notification manager
|
|
122
121
|
notification_manager = context.getSystemService(context.NOTIFICATION_SERVICE)
|
{android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/internal/java_classes.py
RENAMED
|
@@ -39,31 +39,24 @@ 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")
|
|
42
43
|
except Exception as e:
|
|
43
44
|
from .facade import *
|
|
44
45
|
logger.exception("Didn't get Basic Java Classes")
|
|
45
46
|
|
|
46
47
|
# noinspection PyBroadException
|
|
47
48
|
try:
|
|
48
|
-
NotificationManagerCompat =
|
|
49
|
-
NotificationCompat = autoclass(
|
|
50
|
-
NotificationCompatBuilder = autoclass('
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
-
""")
|
|
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')
|
|
65
55
|
|
|
56
|
+
except Exception as styles_import_error:
|
|
57
|
+
logger.exception(styles_import_error)
|
|
66
58
|
from .facade import *
|
|
59
|
+
|
|
67
60
|
else:
|
|
68
61
|
cast = lambda x, y: x
|
|
69
62
|
autoclass = lambda x: None
|
{android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/internal/permissions.py
RENAMED
|
@@ -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, NotificationManagerCompat
|
|
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
|
|
|
@@ -19,10 +19,10 @@ def has_notification_permission():
|
|
|
19
19
|
|
|
20
20
|
if BuildVersion.SDK_INT < 33: # Android 12 and below
|
|
21
21
|
try:
|
|
22
|
+
# NotificationManagerCompat is actually NotificationManager from android_notify.internal.java_classes
|
|
22
23
|
context = get_python_activity_context()
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
return compat_manager.areNotificationsEnabled()
|
|
24
|
+
nm = context.getSystemService(NotificationManagerCompat)
|
|
25
|
+
return nm.areNotificationsEnabled()
|
|
26
26
|
except Exception as error_checking_permission:
|
|
27
27
|
logger.exception(f"On Android 12 and below Error checking permission: {error_checking_permission}")
|
|
28
28
|
return None
|
|
@@ -30,10 +30,8 @@ def has_notification_permission():
|
|
|
30
30
|
if on_flet_app():
|
|
31
31
|
context = get_python_activity_context()
|
|
32
32
|
permission = Manifest.POST_NOTIFICATIONS
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
# in proguard-rules.pro add `-keep class androidx.core.app.ActivityCompat { *; }`
|
|
36
|
-
return ContextCompat.checkSelfPermission(context, permission)
|
|
33
|
+
|
|
34
|
+
return PackageManager.PERMISSION_GRANTED == context.checkSelfPermission(permission)
|
|
37
35
|
else:
|
|
38
36
|
from android.permissions import Permission, check_permission # type: ignore
|
|
39
37
|
return check_permission(Permission.POST_NOTIFICATIONS)
|
|
@@ -82,21 +80,10 @@ def ask_notification_permission(callback=None, set_requesting_state=None, legacy
|
|
|
82
80
|
execute_callback(callback, grants[0])
|
|
83
81
|
execute_callback(set_requesting_state, False,from_who="package")
|
|
84
82
|
|
|
85
|
-
if legacy:
|
|
83
|
+
if legacy or on_flet_app():
|
|
86
84
|
# TODO Handle activity with request code
|
|
87
|
-
PackageManager = autoclass("android.content.pm.PackageManager")
|
|
88
|
-
permission = Manifest.POST_NOTIFICATIONS
|
|
89
|
-
|
|
90
|
-
granted = context.checkSelfPermission(permission)
|
|
91
|
-
if granted != PackageManager.PERMISSION_GRANTED:
|
|
92
|
-
context.requestPermissions([permission], 101)
|
|
93
|
-
return None
|
|
94
|
-
elif on_flet_app():
|
|
95
|
-
# TODO Callback when user answers request question
|
|
96
|
-
# Can't bind activity result method is from p4a which is only on kivy
|
|
97
|
-
ActivityCompat = autoclass('androidx.core.app.ActivityCompat')
|
|
98
85
|
permission = Manifest.POST_NOTIFICATIONS
|
|
99
|
-
|
|
86
|
+
context.requestPermissions([permission], 101)
|
|
100
87
|
return None
|
|
101
88
|
else:
|
|
102
89
|
from android.permissions import request_permissions, Permission # type: ignore
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
""" Non-Advanced Stuff """
|
|
2
|
+
import random
|
|
3
|
+
import os
|
|
4
|
+
ON_ANDROID = False
|
|
5
|
+
|
|
6
|
+
def on_flet_app():
|
|
7
|
+
return os.getenv("MAIN_ACTIVITY_HOST_CLASS_NAME")
|
|
8
|
+
|
|
9
|
+
def get_activity_class_name():
|
|
10
|
+
ACTIVITY_CLASS_NAME = os.getenv("MAIN_ACTIVITY_HOST_CLASS_NAME") # flet python
|
|
11
|
+
if not ACTIVITY_CLASS_NAME:
|
|
12
|
+
try:
|
|
13
|
+
from android import config
|
|
14
|
+
ACTIVITY_CLASS_NAME = getattr(config, "JAVA_NAMESPACE", None)
|
|
15
|
+
except (ImportError, AttributeError):
|
|
16
|
+
ACTIVITY_CLASS_NAME = 'org.kivy.android'
|
|
17
|
+
return ACTIVITY_CLASS_NAME
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
|
|
21
|
+
from jnius import autoclass # Needs Java to be installed
|
|
22
|
+
# Get the required Java classes
|
|
23
|
+
ACTIVITY_CLASS_NAME = get_activity_class_name()
|
|
24
|
+
PythonActivity = autoclass(ACTIVITY_CLASS_NAME)
|
|
25
|
+
context = PythonActivity.mActivity # Get the app's context
|
|
26
|
+
NotificationChannel = autoclass('android.app.NotificationChannel')
|
|
27
|
+
String = autoclass('java.lang.String')
|
|
28
|
+
Intent = autoclass('android.content.Intent')
|
|
29
|
+
PendingIntent = autoclass('android.app.PendingIntent')
|
|
30
|
+
BitmapFactory = autoclass('android.graphics.BitmapFactory')
|
|
31
|
+
BuildVersion = autoclass('android.os.Build$VERSION')
|
|
32
|
+
ON_ANDROID=True
|
|
33
|
+
except Exception as e:
|
|
34
|
+
print('\nThis Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" to see design patterns and more info.\n')
|
|
35
|
+
|
|
36
|
+
if ON_ANDROID:
|
|
37
|
+
try:
|
|
38
|
+
NotificationManagerCompat = autoclass('androidx.core.app.NotificationManagerCompat')
|
|
39
|
+
NotificationCompat = autoclass('androidx.core.app.NotificationCompat')
|
|
40
|
+
|
|
41
|
+
# Notification Design
|
|
42
|
+
NotificationCompatBuilder = autoclass('androidx.core.app.NotificationCompat$Builder')
|
|
43
|
+
NotificationCompatBigTextStyle = autoclass('androidx.core.app.NotificationCompat$BigTextStyle')
|
|
44
|
+
NotificationCompatBigPictureStyle = autoclass('androidx.core.app.NotificationCompat$BigPictureStyle')
|
|
45
|
+
NotificationCompatInboxStyle = autoclass('androidx.core.app.NotificationCompat$InboxStyle')
|
|
46
|
+
except Exception as e:
|
|
47
|
+
print("""\n
|
|
48
|
+
Dependency Error: Add the following in buildozer.spec:
|
|
49
|
+
* android.gradle_dependencies = androidx.core:core-ktx:1.15.0, androidx.core:core:1.6.0
|
|
50
|
+
* android.enable_androidx = True
|
|
51
|
+
* android.permissions = POST_NOTIFICATIONS\n
|
|
52
|
+
""")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_app_root_path():
|
|
56
|
+
if on_flet_app():
|
|
57
|
+
return os.path.join(context.getFilesDir().getAbsolutePath(),'flet')
|
|
58
|
+
else:
|
|
59
|
+
from android.storage import app_storage_path # type: ignore
|
|
60
|
+
return app_storage_path()
|
|
61
|
+
|
|
62
|
+
def asks_permission_if_needed():
|
|
63
|
+
"""
|
|
64
|
+
Ask for permission to send notifications if needed.
|
|
65
|
+
"""
|
|
66
|
+
if on_flet_app():
|
|
67
|
+
VERSION_CODES = autoclass('android.os.Build$VERSION_CODES')
|
|
68
|
+
ContextCompat = autoclass('androidx.core.content.ContextCompat')
|
|
69
|
+
# if you get error `Failed to find class: androidx/core/app/ActivityCompat`
|
|
70
|
+
#in proguard-rules.pro add `-keep class androidx.core.app.ActivityCompat { *; }`
|
|
71
|
+
ActivityCompat = autoclass('androidx.core.app.ActivityCompat')
|
|
72
|
+
Manifest = autoclass('android.Manifest$permission')
|
|
73
|
+
VERSION_CODES = autoclass('android.os.Build$VERSION_CODES')
|
|
74
|
+
|
|
75
|
+
if BuildVersion.SDK_INT >= VERSION_CODES.TIRAMISU:
|
|
76
|
+
permission = Manifest.POST_NOTIFICATIONS
|
|
77
|
+
granted = ContextCompat.checkSelfPermission(context, permission)
|
|
78
|
+
|
|
79
|
+
if granted != 0: # PackageManager.PERMISSION_GRANTED == 0
|
|
80
|
+
ActivityCompat.requestPermissions(context, [permission], 101)
|
|
81
|
+
else: # android package is from p4a which is for kivy
|
|
82
|
+
try:
|
|
83
|
+
from android.permissions import request_permissions, Permission,check_permission # type: ignore
|
|
84
|
+
permissions=[Permission.POST_NOTIFICATIONS]
|
|
85
|
+
if not all(check_permission(p) for p in permissions):
|
|
86
|
+
request_permissions(permissions)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
print("android_notify- error trying to request notification access: ", e)
|
|
89
|
+
|
|
90
|
+
def get_image_uri(relative_path):
|
|
91
|
+
"""
|
|
92
|
+
Get the absolute URI for an image in the assets folder.
|
|
93
|
+
:param relative_path: The relative path to the image (e.g., 'assets/imgs/icon.png').
|
|
94
|
+
:return: Absolute URI java Object (e.g., 'file:///path/to/file.png').
|
|
95
|
+
"""
|
|
96
|
+
app_root_path = get_app_root_path()
|
|
97
|
+
output_path = os.path.join(app_root_path,'app', relative_path)
|
|
98
|
+
# print(output_path,'output_path') # /data/user/0/org.laner.lan_ft/files/app/assets/imgs/icon.png
|
|
99
|
+
|
|
100
|
+
if not os.path.exists(output_path):
|
|
101
|
+
raise FileNotFoundError(f"\nImage not found at path: {output_path}\n")
|
|
102
|
+
|
|
103
|
+
Uri = autoclass('android.net.Uri')
|
|
104
|
+
return Uri.parse(f"file://{output_path}")
|
|
105
|
+
|
|
106
|
+
def get_icon_object(uri):
|
|
107
|
+
BitmapFactory = autoclass('android.graphics.BitmapFactory')
|
|
108
|
+
IconCompat = autoclass('androidx.core.graphics.drawable.IconCompat')
|
|
109
|
+
|
|
110
|
+
bitmap= BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri))
|
|
111
|
+
return IconCompat.createWithBitmap(bitmap)
|
|
112
|
+
|
|
113
|
+
def insert_app_icon(builder,custom_icon_path):
|
|
114
|
+
if custom_icon_path:
|
|
115
|
+
try:
|
|
116
|
+
uri = get_image_uri(custom_icon_path)
|
|
117
|
+
icon = get_icon_object(uri)
|
|
118
|
+
builder.setSmallIcon(icon)
|
|
119
|
+
except Exception as e:
|
|
120
|
+
print('android_notify- error: ',e)
|
|
121
|
+
builder.setSmallIcon(context.getApplicationInfo().icon)
|
|
122
|
+
else:
|
|
123
|
+
print('Found res icon -->',context.getApplicationInfo().icon,'<--')
|
|
124
|
+
builder.setSmallIcon(context.getApplicationInfo().icon)
|
|
125
|
+
|
|
126
|
+
def send_notification(
|
|
127
|
+
title:str,
|
|
128
|
+
message:str,
|
|
129
|
+
style=None,
|
|
130
|
+
img_path=None,
|
|
131
|
+
channel_name="Default Channel",
|
|
132
|
+
channel_id:str="default_channel",
|
|
133
|
+
custom_app_icon_path="",
|
|
134
|
+
|
|
135
|
+
big_picture_path='',
|
|
136
|
+
large_icon_path='',
|
|
137
|
+
big_text="",
|
|
138
|
+
lines=""
|
|
139
|
+
):
|
|
140
|
+
"""
|
|
141
|
+
Send a notification on Android.
|
|
142
|
+
|
|
143
|
+
:param title: Title of the notification.
|
|
144
|
+
:param message: Message body.
|
|
145
|
+
:param style: Style of the notification ('big_text', 'big_picture', 'inbox', 'large_icon').
|
|
146
|
+
:param img_path: Path to the image resource.
|
|
147
|
+
:param channel_id: Notification channel ID.(Default is lowercase channel name arg in lowercase)
|
|
148
|
+
"""
|
|
149
|
+
if not ON_ANDROID:
|
|
150
|
+
print('This Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" for Documentation.')
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
asks_permission_if_needed()
|
|
154
|
+
channel_id=channel_name.replace(' ','_').lower().lower() if not channel_id else channel_id
|
|
155
|
+
# Get notification manager
|
|
156
|
+
notification_manager = context.getSystemService(context.NOTIFICATION_SERVICE)
|
|
157
|
+
|
|
158
|
+
# importance= autoclass('android.app.NotificationManager').IMPORTANCE_HIGH # also works #NotificationManager.IMPORTANCE_DEFAULT
|
|
159
|
+
importance= NotificationManagerCompat.IMPORTANCE_HIGH #autoclass('android.app.NotificationManager').IMPORTANCE_HIGH also works #NotificationManager.IMPORTANCE_DEFAULT
|
|
160
|
+
|
|
161
|
+
# Notification Channel (Required for Android 8.0+)
|
|
162
|
+
if BuildVersion.SDK_INT >= 26:
|
|
163
|
+
channel = NotificationChannel(channel_id, channel_name,importance)
|
|
164
|
+
notification_manager.createNotificationChannel(channel)
|
|
165
|
+
|
|
166
|
+
# Build the notification
|
|
167
|
+
builder = NotificationCompatBuilder(context, channel_id)
|
|
168
|
+
builder.setContentTitle(title)
|
|
169
|
+
builder.setContentText(message)
|
|
170
|
+
insert_app_icon(builder,custom_app_icon_path)
|
|
171
|
+
builder.setDefaults(NotificationCompat.DEFAULT_ALL)
|
|
172
|
+
builder.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
173
|
+
|
|
174
|
+
if img_path:
|
|
175
|
+
print('android_notify- img_path arg deprecated use "large_icon_path or big_picture_path or custom_app_icon_path"instead ')
|
|
176
|
+
|
|
177
|
+
big_picture = None
|
|
178
|
+
if big_picture_path:
|
|
179
|
+
try:
|
|
180
|
+
big_picture = get_image_uri(big_picture_path)
|
|
181
|
+
except FileNotFoundError as e:
|
|
182
|
+
print('android_notify- Error Getting Uri for big_picture_path: ',e)
|
|
183
|
+
|
|
184
|
+
large_icon = None
|
|
185
|
+
if large_icon_path:
|
|
186
|
+
try:
|
|
187
|
+
large_icon = get_image_uri(large_icon_path)
|
|
188
|
+
except FileNotFoundError as e:
|
|
189
|
+
print('android_notify- Error Getting Uri for large_icon_path: ',e)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
# Apply notification styles
|
|
193
|
+
try:
|
|
194
|
+
if big_text:
|
|
195
|
+
big_text_style = NotificationCompatBigTextStyle()
|
|
196
|
+
big_text_style.bigText(big_text)
|
|
197
|
+
builder.setStyle(big_text_style)
|
|
198
|
+
|
|
199
|
+
elif lines:
|
|
200
|
+
inbox_style = NotificationCompatInboxStyle()
|
|
201
|
+
for line in lines.split("\n"):
|
|
202
|
+
inbox_style.addLine(line)
|
|
203
|
+
builder.setStyle(inbox_style)
|
|
204
|
+
|
|
205
|
+
if large_icon:
|
|
206
|
+
bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(large_icon))
|
|
207
|
+
builder.setLargeIcon(bitmap)
|
|
208
|
+
|
|
209
|
+
if big_picture:
|
|
210
|
+
bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(big_picture))
|
|
211
|
+
builder.setLargeIcon(bitmap)
|
|
212
|
+
big_picture_style = NotificationCompatBigPictureStyle().bigPicture(bitmap)
|
|
213
|
+
builder.setStyle(big_picture_style)
|
|
214
|
+
|
|
215
|
+
except Exception as e:
|
|
216
|
+
print('android_notify- Error Failed Adding Style: ',e)
|
|
217
|
+
# Display the notification
|
|
218
|
+
notification_id = random.randint(0, 100)
|
|
219
|
+
notification_manager.notify(notification_id, builder.build())
|
|
220
|
+
return notification_id
|
|
221
|
+
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
""" Non-Advanced Stuff """
|
|
2
|
+
import random
|
|
3
|
+
import os
|
|
4
|
+
ON_ANDROID = False
|
|
5
|
+
|
|
6
|
+
def on_flet_app():
|
|
7
|
+
return os.getenv("MAIN_ACTIVITY_HOST_CLASS_NAME")
|
|
8
|
+
|
|
9
|
+
def get_activity_class_name():
|
|
10
|
+
ACTIVITY_CLASS_NAME = os.getenv("MAIN_ACTIVITY_HOST_CLASS_NAME") # flet python
|
|
11
|
+
if not ACTIVITY_CLASS_NAME:
|
|
12
|
+
try:
|
|
13
|
+
from android import config
|
|
14
|
+
ACTIVITY_CLASS_NAME = getattr(config, "JAVA_NAMESPACE", None)
|
|
15
|
+
except (ImportError, AttributeError):
|
|
16
|
+
ACTIVITY_CLASS_NAME = 'org.kivy.android'
|
|
17
|
+
return ACTIVITY_CLASS_NAME
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
|
|
21
|
+
from jnius import autoclass # Needs Java to be installed
|
|
22
|
+
# Get the required Java classes
|
|
23
|
+
ACTIVITY_CLASS_NAME = get_activity_class_name()
|
|
24
|
+
PythonActivity = autoclass(ACTIVITY_CLASS_NAME)
|
|
25
|
+
context = PythonActivity.mActivity # Get the app's context
|
|
26
|
+
NotificationChannel = autoclass('android.app.NotificationChannel')
|
|
27
|
+
String = autoclass('java.lang.String')
|
|
28
|
+
Intent = autoclass('android.content.Intent')
|
|
29
|
+
PendingIntent = autoclass('android.app.PendingIntent')
|
|
30
|
+
BitmapFactory = autoclass('android.graphics.BitmapFactory')
|
|
31
|
+
BuildVersion = autoclass('android.os.Build$VERSION')
|
|
32
|
+
ON_ANDROID=True
|
|
33
|
+
except Exception as e:
|
|
34
|
+
print('\nThis Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" to see design patterns and more info.\n')
|
|
35
|
+
|
|
36
|
+
if ON_ANDROID:
|
|
37
|
+
try:
|
|
38
|
+
NotificationManagerCompat = autoclass('androidx.core.app.NotificationManagerCompat')
|
|
39
|
+
NotificationCompat = autoclass('androidx.core.app.NotificationCompat')
|
|
40
|
+
|
|
41
|
+
# Notification Design
|
|
42
|
+
NotificationCompatBuilder = autoclass('androidx.core.app.NotificationCompat$Builder')
|
|
43
|
+
NotificationCompatBigTextStyle = autoclass('androidx.core.app.NotificationCompat$BigTextStyle')
|
|
44
|
+
NotificationCompatBigPictureStyle = autoclass('androidx.core.app.NotificationCompat$BigPictureStyle')
|
|
45
|
+
NotificationCompatInboxStyle = autoclass('androidx.core.app.NotificationCompat$InboxStyle')
|
|
46
|
+
except Exception as e:
|
|
47
|
+
print("""\n
|
|
48
|
+
Dependency Error: Add the following in buildozer.spec:
|
|
49
|
+
* android.gradle_dependencies = androidx.core:core-ktx:1.15.0, androidx.core:core:1.6.0
|
|
50
|
+
* android.enable_androidx = True
|
|
51
|
+
* android.permissions = POST_NOTIFICATIONS\n
|
|
52
|
+
""")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_app_root_path():
|
|
56
|
+
if on_flet_app():
|
|
57
|
+
return os.path.join(context.getFilesDir().getAbsolutePath(),'flet')
|
|
58
|
+
else:
|
|
59
|
+
from android.storage import app_storage_path # type: ignore
|
|
60
|
+
return app_storage_path()
|
|
61
|
+
|
|
62
|
+
def asks_permission_if_needed():
|
|
63
|
+
"""
|
|
64
|
+
Ask for permission to send notifications if needed.
|
|
65
|
+
"""
|
|
66
|
+
if on_flet_app():
|
|
67
|
+
VERSION_CODES = autoclass('android.os.Build$VERSION_CODES')
|
|
68
|
+
ContextCompat = autoclass('androidx.core.content.ContextCompat')
|
|
69
|
+
# if you get error `Failed to find class: androidx/core/app/ActivityCompat`
|
|
70
|
+
#in proguard-rules.pro add `-keep class androidx.core.app.ActivityCompat { *; }`
|
|
71
|
+
ActivityCompat = autoclass('androidx.core.app.ActivityCompat')
|
|
72
|
+
Manifest = autoclass('android.Manifest$permission')
|
|
73
|
+
VERSION_CODES = autoclass('android.os.Build$VERSION_CODES')
|
|
74
|
+
|
|
75
|
+
if BuildVersion.SDK_INT >= VERSION_CODES.TIRAMISU:
|
|
76
|
+
permission = Manifest.POST_NOTIFICATIONS
|
|
77
|
+
granted = ContextCompat.checkSelfPermission(context, permission)
|
|
78
|
+
|
|
79
|
+
if granted != 0: # PackageManager.PERMISSION_GRANTED == 0
|
|
80
|
+
ActivityCompat.requestPermissions(context, [permission], 101)
|
|
81
|
+
else: # android package is from p4a which is for kivy
|
|
82
|
+
try:
|
|
83
|
+
from android.permissions import request_permissions, Permission,check_permission # type: ignore
|
|
84
|
+
permissions=[Permission.POST_NOTIFICATIONS]
|
|
85
|
+
if not all(check_permission(p) for p in permissions):
|
|
86
|
+
request_permissions(permissions)
|
|
87
|
+
except Exception as e:
|
|
88
|
+
print("android_notify- error trying to request notification access: ", e)
|
|
89
|
+
|
|
90
|
+
def get_image_uri(relative_path):
|
|
91
|
+
"""
|
|
92
|
+
Get the absolute URI for an image in the assets folder.
|
|
93
|
+
:param relative_path: The relative path to the image (e.g., 'assets/imgs/icon.png').
|
|
94
|
+
:return: Absolute URI java Object (e.g., 'file:///path/to/file.png').
|
|
95
|
+
"""
|
|
96
|
+
app_root_path = get_app_root_path()
|
|
97
|
+
output_path = os.path.join(app_root_path,'app', relative_path)
|
|
98
|
+
# print(output_path,'output_path') # /data/user/0/org.laner.lan_ft/files/app/assets/imgs/icon.png
|
|
99
|
+
|
|
100
|
+
if not os.path.exists(output_path):
|
|
101
|
+
raise FileNotFoundError(f"\nImage not found at path: {output_path}\n")
|
|
102
|
+
|
|
103
|
+
Uri = autoclass('android.net.Uri')
|
|
104
|
+
return Uri.parse(f"file://{output_path}")
|
|
105
|
+
|
|
106
|
+
def get_icon_object(uri):
|
|
107
|
+
BitmapFactory = autoclass('android.graphics.BitmapFactory')
|
|
108
|
+
IconCompat = autoclass('androidx.core.graphics.drawable.IconCompat')
|
|
109
|
+
|
|
110
|
+
bitmap= BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri))
|
|
111
|
+
return IconCompat.createWithBitmap(bitmap)
|
|
112
|
+
|
|
113
|
+
def insert_app_icon(builder,custom_icon_path):
|
|
114
|
+
if custom_icon_path:
|
|
115
|
+
try:
|
|
116
|
+
uri = get_image_uri(custom_icon_path)
|
|
117
|
+
icon = get_icon_object(uri)
|
|
118
|
+
builder.setSmallIcon(icon)
|
|
119
|
+
except Exception as e:
|
|
120
|
+
print('android_notify- error: ',e)
|
|
121
|
+
builder.setSmallIcon(context.getApplicationInfo().icon)
|
|
122
|
+
else:
|
|
123
|
+
print('Found res icon -->',context.getApplicationInfo().icon,'<--')
|
|
124
|
+
builder.setSmallIcon(context.getApplicationInfo().icon)
|
|
125
|
+
|
|
126
|
+
def send_notification(
|
|
127
|
+
title:str,
|
|
128
|
+
message:str,
|
|
129
|
+
style=None,
|
|
130
|
+
img_path=None,
|
|
131
|
+
channel_name="Default Channel",
|
|
132
|
+
channel_id:str="default_channel",
|
|
133
|
+
custom_app_icon_path="",
|
|
134
|
+
|
|
135
|
+
big_picture_path='',
|
|
136
|
+
large_icon_path='',
|
|
137
|
+
big_text="",
|
|
138
|
+
lines=""
|
|
139
|
+
):
|
|
140
|
+
"""
|
|
141
|
+
Send a notification on Android.
|
|
142
|
+
|
|
143
|
+
:param title: Title of the notification.
|
|
144
|
+
:param message: Message body.
|
|
145
|
+
:param style: Style of the notification ('big_text', 'big_picture', 'inbox', 'large_icon').
|
|
146
|
+
:param img_path: Path to the image resource.
|
|
147
|
+
:param channel_id: Notification channel ID.(Default is lowercase channel name arg in lowercase)
|
|
148
|
+
"""
|
|
149
|
+
if not ON_ANDROID:
|
|
150
|
+
print('This Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" for Documentation.')
|
|
151
|
+
return
|
|
152
|
+
|
|
153
|
+
asks_permission_if_needed()
|
|
154
|
+
channel_id=channel_name.replace(' ','_').lower().lower() if not channel_id else channel_id
|
|
155
|
+
# Get notification manager
|
|
156
|
+
notification_manager = context.getSystemService(context.NOTIFICATION_SERVICE)
|
|
157
|
+
|
|
158
|
+
# importance= autoclass('android.app.NotificationManager').IMPORTANCE_HIGH # also works #NotificationManager.IMPORTANCE_DEFAULT
|
|
159
|
+
importance= NotificationManagerCompat.IMPORTANCE_HIGH #autoclass('android.app.NotificationManager').IMPORTANCE_HIGH also works #NotificationManager.IMPORTANCE_DEFAULT
|
|
160
|
+
|
|
161
|
+
# Notification Channel (Required for Android 8.0+)
|
|
162
|
+
if BuildVersion.SDK_INT >= 26:
|
|
163
|
+
channel = NotificationChannel(channel_id, channel_name,importance)
|
|
164
|
+
notification_manager.createNotificationChannel(channel)
|
|
165
|
+
|
|
166
|
+
# Build the notification
|
|
167
|
+
builder = NotificationCompatBuilder(context, channel_id)
|
|
168
|
+
builder.setContentTitle(title)
|
|
169
|
+
builder.setContentText(message)
|
|
170
|
+
insert_app_icon(builder,custom_app_icon_path)
|
|
171
|
+
builder.setDefaults(NotificationCompat.DEFAULT_ALL)
|
|
172
|
+
builder.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
173
|
+
|
|
174
|
+
if img_path:
|
|
175
|
+
print('android_notify- img_path arg deprecated use "large_icon_path or big_picture_path or custom_app_icon_path"instead ')
|
|
176
|
+
|
|
177
|
+
big_picture = None
|
|
178
|
+
if big_picture_path:
|
|
179
|
+
try:
|
|
180
|
+
big_picture = get_image_uri(big_picture_path)
|
|
181
|
+
except FileNotFoundError as e:
|
|
182
|
+
print('android_notify- Error Getting Uri for big_picture_path: ',e)
|
|
183
|
+
|
|
184
|
+
large_icon = None
|
|
185
|
+
if large_icon_path:
|
|
186
|
+
try:
|
|
187
|
+
large_icon = get_image_uri(large_icon_path)
|
|
188
|
+
except FileNotFoundError as e:
|
|
189
|
+
print('android_notify- Error Getting Uri for large_icon_path: ',e)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
# Apply notification styles
|
|
193
|
+
try:
|
|
194
|
+
if big_text:
|
|
195
|
+
big_text_style = NotificationCompatBigTextStyle()
|
|
196
|
+
big_text_style.bigText(big_text)
|
|
197
|
+
builder.setStyle(big_text_style)
|
|
198
|
+
|
|
199
|
+
elif lines:
|
|
200
|
+
inbox_style = NotificationCompatInboxStyle()
|
|
201
|
+
for line in lines.split("\n"):
|
|
202
|
+
inbox_style.addLine(line)
|
|
203
|
+
builder.setStyle(inbox_style)
|
|
204
|
+
|
|
205
|
+
if large_icon:
|
|
206
|
+
bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(large_icon))
|
|
207
|
+
builder.setLargeIcon(bitmap)
|
|
208
|
+
|
|
209
|
+
if big_picture:
|
|
210
|
+
bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(big_picture))
|
|
211
|
+
builder.setLargeIcon(bitmap)
|
|
212
|
+
big_picture_style = NotificationCompatBigPictureStyle().bigPicture(bitmap)
|
|
213
|
+
builder.setStyle(big_picture_style)
|
|
214
|
+
|
|
215
|
+
except Exception as e:
|
|
216
|
+
print('android_notify- Error Failed Adding Style: ',e)
|
|
217
|
+
# Display the notification
|
|
218
|
+
notification_id = random.randint(0, 100)
|
|
219
|
+
notification_manager.notify(notification_id, builder.build())
|
|
220
|
+
return notification_id
|
|
221
|
+
|
|
@@ -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
|
|
8
8
|
from android_notify.internal.helper import get_package_path
|
|
9
9
|
from android_notify.internal.logger import logger
|
|
10
10
|
|
|
@@ -128,6 +128,7 @@ def set_small_icon_with_bitmap(bitmap, builder):
|
|
|
128
128
|
logger.warning("Bitmap Insert as Icon Not available below Android 6")
|
|
129
129
|
return False
|
|
130
130
|
try:
|
|
131
|
+
IconCompat = autoclass('android.graphics.drawable.Icon')
|
|
131
132
|
icon = IconCompat.createWithBitmap(bitmap)
|
|
132
133
|
builder.setSmallIcon(icon)
|
|
133
134
|
return True
|
|
@@ -106,7 +106,7 @@ def set_lines(builder, lines):
|
|
|
106
106
|
|
|
107
107
|
|
|
108
108
|
|
|
109
|
-
from android_notify.internal.java_classes import Color, RemoteViews
|
|
109
|
+
from android_notify.internal.java_classes import Color, RemoteViews
|
|
110
110
|
from android_notify.internal.logger import logger
|
|
111
111
|
from android_notify.config import get_python_activity_context
|
|
112
112
|
|
|
@@ -121,6 +121,10 @@ def setLayoutText(layout, text_id, text, color):
|
|
|
121
121
|
|
|
122
122
|
def set_custom_colors(builder, title, message, title_color, message_color):
|
|
123
123
|
# Load layout
|
|
124
|
+
from android_notify.internal.java_classes import autoclass
|
|
125
|
+
NotificationCompatDecoratedCustomViewStyle = autoclass(
|
|
126
|
+
'android.app.Notification$DecoratedCustomViewStyle')
|
|
127
|
+
|
|
124
128
|
context = get_python_activity_context()
|
|
125
129
|
resources = context.getResources()
|
|
126
130
|
package_name = context.getPackageName()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: android-notify
|
|
3
|
-
Version: 1.60.10
|
|
3
|
+
Version: 1.60.10.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,14 +81,9 @@ 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
|
|
84
|
+
requirements = python3, kivy, pyjnius, android-notify==1.60.10.dev0
|
|
85
85
|
# Add permission for notifications
|
|
86
86
|
android.permissions = POST_NOTIFICATIONS
|
|
87
|
-
|
|
88
|
-
# Required dependency (write exactly as shown, no quotation marks)
|
|
89
|
-
android.gradle_dependencies = androidx.core:core-ktx:1.15.0
|
|
90
|
-
android.enable_androidx = True
|
|
91
|
-
android.api = 35
|
|
92
87
|
```
|
|
93
88
|
|
|
94
89
|
</details>
|
|
@@ -98,7 +93,7 @@ android.api = 35
|
|
|
98
93
|
<summary><b>Flet apps:</b></summary>
|
|
99
94
|
<br/>
|
|
100
95
|
|
|
101
|
-
|
|
96
|
+
In your `pyproject.toml` file, ensure you include the following:
|
|
102
97
|
|
|
103
98
|
|
|
104
99
|
```toml
|
|
@@ -114,35 +109,7 @@ dependencies = [
|
|
|
114
109
|
|
|
115
110
|
</details>
|
|
116
111
|
|
|
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.10.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.10.dev0
|
|
143
|
-
```
|
|
144
112
|
|
|
145
|
-
</details>
|
|
146
113
|
|
|
147
114
|
<details>
|
|
148
115
|
|
|
@@ -193,11 +160,23 @@ if __name__ == "__main__":
|
|
|
193
160
|
</details>
|
|
194
161
|
|
|
195
162
|
|
|
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>
|
|
196
175
|
|
|
197
176
|
## Documentation
|
|
198
|
-
For Dev Version
|
|
177
|
+
For Dev Version use
|
|
199
178
|
```ini
|
|
200
|
-
requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/
|
|
179
|
+
requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_notify/archive/without-androidx.zip
|
|
201
180
|
```
|
|
202
181
|
|
|
203
182
|
<details>
|
|
@@ -206,7 +185,7 @@ requirements = python3, kivy, pyjnius, https://github.com/Fector101/android_noti
|
|
|
206
185
|
- Make things happen without being in your app
|
|
207
186
|
```python
|
|
208
187
|
from android_notify import Notification
|
|
209
|
-
notification = Notification(title="
|
|
188
|
+
notification = Notification(title="Receiver Notification")
|
|
210
189
|
notification.addButton(text="Stop", receiver_name="CarouselReceiver", action="ACTION_STOP")
|
|
211
190
|
notification.addButton(text="Skip", receiver_name="CarouselReceiver", action="ACTION_SKIP")
|
|
212
191
|
```
|
|
@@ -269,7 +248,7 @@ Notification.createChannel(id='shake', name="Shake Passage", vibrate=True)
|
|
|
269
248
|
|
|
270
249
|
n=Notification(title='Vibrate',channel_id='shake')
|
|
271
250
|
n.setVibrate() # for less than android 8
|
|
272
|
-
n.fVibrate() # To Force Vibrate
|
|
251
|
+
n.fVibrate() # To Force Vibrate (when user turned off in settings)
|
|
273
252
|
n.send()
|
|
274
253
|
```
|
|
275
254
|
|
|
@@ -307,5 +286,9 @@ from android_notify import Notification, NotificationHandler
|
|
|
307
286
|
|
|
308
287
|
## ☕ Support the Project
|
|
309
288
|
|
|
310
|
-
If you find this project helpful,
|
|
311
|
-
[
|
|
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>
|
|
@@ -41,7 +41,9 @@ android_notify/tests/test_notification_styles.py
|
|
|
41
41
|
android_notify/tests/flet/adv/main.py
|
|
42
42
|
android_notify/tests/flet/adv/tests/__init__.py
|
|
43
43
|
android_notify/tests/flet/adv/tests/test_android_notify_full.py
|
|
44
|
+
android_notify/tests/flet/basic/src/core.py
|
|
44
45
|
android_notify/tests/flet/basic/src/main.py
|
|
46
|
+
android_notify/tests/flet/flet-working/src/core.py
|
|
45
47
|
android_notify/tests/flet/flet-working/src/main.py
|
|
46
48
|
android_notify/tests/p4a/hook.py
|
|
47
49
|
android_notify/tests/serivces/wallpaper.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "android-notify"
|
|
7
|
-
version = "1.60.10"
|
|
7
|
+
version = "1.60.10.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 = [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/android_notify_test.py
RENAMED
|
File without changes
|
|
File without changes
|
{android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/flet/adv/main.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/flet/basic/src/main.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify/tests/serivces/wallpaper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
{android_notify-1.60.10 → android_notify-1.60.10.dev0}/android_notify.egg-info/top_level.txt
RENAMED
|
File without changes
|
{android_notify-1.60.10 → android_notify-1.60.10.dev0}/docs/website/src/pages/data/laner_Sent.py
RENAMED
|
File without changes
|
|
File without changes
|