android-notify 1.59.4__py3-none-any.whl → 1.60.1__py3-none-any.whl

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/core.py CHANGED
@@ -1,139 +1,227 @@
1
- """ Non-Advanced Stuff """
2
- import random
3
- import os
4
- ON_ANDROID = False
5
- try:
6
- from jnius import autoclass,cast # Needs Java to be installed
7
- # Get the required Java classes
8
- PythonActivity = autoclass('org.kivy.android.PythonActivity')
9
- NotificationChannel = autoclass('android.app.NotificationChannel')
10
- String = autoclass('java.lang.String')
11
- Intent = autoclass('android.content.Intent')
12
- PendingIntent = autoclass('android.app.PendingIntent')
13
- context = PythonActivity.mActivity # Get the app's context
14
- BitmapFactory = autoclass('android.graphics.BitmapFactory')
15
- BuildVersion = autoclass('android.os.Build$VERSION')
16
- ON_ANDROID=True
17
- except Exception as e:
18
- print('This Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" to see design patterns and more info.')
19
-
20
- if ON_ANDROID:
21
- try:
22
- NotificationManagerCompat = autoclass('androidx.core.app.NotificationManagerCompat')
23
- NotificationCompat = autoclass('androidx.core.app.NotificationCompat')
24
-
25
- # Notification Design
26
- NotificationCompatBuilder = autoclass('androidx.core.app.NotificationCompat$Builder')
27
- NotificationCompatBigTextStyle = autoclass('androidx.core.app.NotificationCompat$BigTextStyle')
28
- NotificationCompatBigPictureStyle = autoclass('androidx.core.app.NotificationCompat$BigPictureStyle')
29
- NotificationCompatInboxStyle = autoclass('androidx.core.app.NotificationCompat$InboxStyle')
30
- except Exception as e:
31
- print("""
32
- Dependency Error: Add the following in buildozer.spec:
33
- * android.gradle_dependencies = androidx.core:core-ktx:1.15.0, androidx.core:core:1.6.0
34
- * android.enable_androidx = True
35
- * android.permissions = POST_NOTIFICATIONS
36
- """)
37
-
38
- def asks_permission_if_needed():
39
- """
40
- Ask for permission to send notifications if needed.
41
- """
42
- from android.permissions import request_permissions, Permission,check_permission # type: ignore
43
-
44
- permissions=[Permission.POST_NOTIFICATIONS]
45
- if not all(check_permission(p) for p in permissions):
46
- request_permissions(permissions)
47
-
48
- def get_image_uri(relative_path):
49
- """
50
- Get the absolute URI for an image in the assets folder.
51
- :param relative_path: The relative path to the image (e.g., 'assets/imgs/icon.png').
52
- :return: Absolute URI java Object (e.g., 'file:///path/to/file.png').
53
- """
54
- from android.storage import app_storage_path # type: ignore
55
-
56
- output_path = os.path.join(app_storage_path(),'app', relative_path)
57
- # print(output_path,'output_path') # /data/user/0/org.laner.lan_ft/files/app/assets/imgs/icon.png
58
-
59
- if not os.path.exists(output_path):
60
- raise FileNotFoundError(f"Image not found at path: {output_path}")
61
-
62
- Uri = autoclass('android.net.Uri')
63
- return Uri.parse(f"file://{output_path}")
64
-
65
-
66
- def send_notification(
67
- title:str,
68
- message:str,
69
- style=None,
70
- img_path=None,
71
- channel_name="Default Channel",
72
- channel_id:str="default_channel"
73
- ):
74
- """
75
- Send a notification on Android.
76
-
77
- :param title: Title of the notification.
78
- :param message: Message body.
79
- :param style: Style of the notification ('big_text', 'big_picture', 'inbox', 'large_icon').
80
- :param img_path: Path to the image resource.
81
- :param channel_id: Notification channel ID.(Default is lowercase channel name arg in lowercase)
82
- """
83
- if not ON_ANDROID:
84
- print('This Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" for Documentation.')
85
- return
86
- asks_permission_if_needed()
87
- channel_id=channel_name.replace(' ','_').lower().lower() if not channel_id else channel_id
88
- # Get notification manager
89
- notification_manager = context.getSystemService(context.NOTIFICATION_SERVICE)
90
-
91
- # importance= autoclass('android.app.NotificationManager').IMPORTANCE_HIGH # also works #NotificationManager.IMPORTANCE_DEFAULT
92
- importance= NotificationManagerCompat.IMPORTANCE_HIGH #autoclass('android.app.NotificationManager').IMPORTANCE_HIGH also works #NotificationManager.IMPORTANCE_DEFAULT
93
-
94
- # Notification Channel (Required for Android 8.0+)
95
- if BuildVersion.SDK_INT >= 26:
96
- channel = NotificationChannel(channel_id, channel_name,importance)
97
- notification_manager.createNotificationChannel(channel)
98
-
99
- # Build the notification
100
- builder = NotificationCompatBuilder(context, channel_id)
101
- builder.setContentTitle(title)
102
- builder.setContentText(message)
103
- builder.setSmallIcon(context.getApplicationInfo().icon)
104
- builder.setDefaults(NotificationCompat.DEFAULT_ALL)
105
- builder.setPriority(NotificationCompat.PRIORITY_HIGH)
106
-
107
- img=None
108
- if img_path:
109
- try:
110
- img = get_image_uri(img_path)
111
- except FileNotFoundError as e:
112
- print('Failed Adding Bitmap: ',e)
113
-
114
- # Apply notification styles
115
- try:
116
- if style == "big_text":
117
- big_text_style = NotificationCompatBigTextStyle()
118
- big_text_style.bigText(message)
119
- builder.setStyle(big_text_style)
120
- elif style == "big_picture" and img_path:
121
- bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(img))
122
- builder.setLargeIcon(bitmap)
123
- big_picture_style = NotificationCompatBigPictureStyle().bigPicture(bitmap)
124
- builder.setStyle(big_picture_style)
125
- elif style == "inbox":
126
- inbox_style = NotificationCompatInboxStyle()
127
- for line in message.split("\n"):
128
- inbox_style.addLine(line)
129
- builder.setStyle(inbox_style)
130
- elif style == "large_icon" and img_path:
131
- bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(img))
132
- builder.setLargeIcon(bitmap)
133
- except Exception as e:
134
- print('Failed Adding Style: ',e)
135
- # Display the notification
136
- notification_id = random.randint(0, 100)
137
- notification_manager.notify(notification_id, builder.build())
138
- return notification_id
139
-
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
+ path = ''
57
+ if on_flet_app():
58
+ path= os.path.join(context.getFilesDir().getAbsolutePath(),'flet')
59
+ else:
60
+ try:
61
+ from android.storage import app_storage_path # type: ignore
62
+ path = app_storage_path()
63
+ except Exception as e:
64
+ print('android-notify- Error getting apk main file path: ',e)
65
+ return './'
66
+ return os.path.join(path,'app')
67
+
68
+ def asks_permission_if_needed():
69
+ """
70
+ Ask for permission to send notifications if needed.
71
+ """
72
+ if on_flet_app():
73
+ ContextCompat = autoclass('androidx.core.content.ContextCompat')
74
+ # if you get error `Failed to find class: androidx/core/app/ActivityCompat`
75
+ #in proguard-rules.pro add `-keep class androidx.core.app.ActivityCompat { *; }`
76
+ ActivityCompat = autoclass('androidx.core.app.ActivityCompat')
77
+ Manifest = autoclass('android.Manifest$permission')
78
+ VERSION_CODES = autoclass('android.os.Build$VERSION_CODES')
79
+
80
+ if BuildVersion.SDK_INT >= VERSION_CODES.TIRAMISU:
81
+ permission = Manifest.POST_NOTIFICATIONS
82
+ granted = ContextCompat.checkSelfPermission(context, permission)
83
+
84
+ if granted != 0: # PackageManager.PERMISSION_GRANTED == 0
85
+ ActivityCompat.requestPermissions(context, [permission], 101)
86
+ else: # android package is from p4a which is for kivy
87
+ try:
88
+ from android.permissions import request_permissions, Permission,check_permission # type: ignore
89
+ permissions=[Permission.POST_NOTIFICATIONS]
90
+ if not all(check_permission(p) for p in permissions):
91
+ request_permissions(permissions)
92
+ except Exception as e:
93
+ print("android_notify- error trying to request notification access: ", e)
94
+
95
+ def get_image_uri(relative_path):
96
+ """
97
+ Get the absolute URI for an image in the assets folder.
98
+ :param relative_path: The relative path to the image (e.g., 'assets/imgs/icon.png').
99
+ :return: Absolute URI java Object (e.g., 'file:///path/to/file.png').
100
+ """
101
+ app_root_path = get_app_root_path()
102
+ output_path = os.path.join(app_root_path, relative_path)
103
+ # print(output_path,'output_path') # /data/user/0/org.laner.lan_ft/files/app/assets/imgs/icon.png
104
+
105
+ if not os.path.exists(output_path):
106
+ raise FileNotFoundError(f"\nImage not found at path: {output_path}\n")
107
+
108
+ Uri = autoclass('android.net.Uri')
109
+ return Uri.parse(f"file://{output_path}")
110
+
111
+ def get_icon_object(uri):
112
+ BitmapFactory = autoclass('android.graphics.BitmapFactory')
113
+ IconCompat = autoclass('androidx.core.graphics.drawable.IconCompat')
114
+
115
+ bitmap= BitmapFactory.decodeStream(context.getContentResolver().openInputStream(uri))
116
+ return IconCompat.createWithBitmap(bitmap)
117
+
118
+ def insert_app_icon(builder,custom_icon_path):
119
+ if custom_icon_path:
120
+ try:
121
+ uri = get_image_uri(custom_icon_path)
122
+ icon = get_icon_object(uri)
123
+ builder.setSmallIcon(icon)
124
+ except Exception as e:
125
+ print('android_notify- error: ',e)
126
+ builder.setSmallIcon(context.getApplicationInfo().icon)
127
+ else:
128
+ # print('Found res icon -->',context.getApplicationInfo().icon,'<--')
129
+ builder.setSmallIcon(context.getApplicationInfo().icon)
130
+
131
+ def send_notification(
132
+ title:str,
133
+ message:str,
134
+ style=None,
135
+ img_path=None,
136
+ channel_name="Default Channel",
137
+ channel_id:str="default_channel",
138
+ custom_app_icon_path="",
139
+
140
+ big_picture_path='',
141
+ large_icon_path='',
142
+ big_text="",
143
+ lines=""
144
+ ):
145
+ """
146
+ Send a notification on Android.
147
+
148
+ :param title: Title of the notification.
149
+ :param message: Message body.
150
+ :param style: deprecated.
151
+ :param img_path: Path to the image resource.
152
+ :param channel_id: Notification channel ID.(Default is lowercase channel name arg in lowercase)
153
+ """
154
+ if not ON_ANDROID:
155
+ print('This Package Only Runs on Android !!! ---> Check "https://github.com/Fector101/android_notify/" for Documentation.')
156
+ return
157
+
158
+ asks_permission_if_needed()
159
+ channel_id=channel_name.replace(' ','_').lower().lower() if not channel_id else channel_id
160
+ # Get notification manager
161
+ notification_manager = context.getSystemService(context.NOTIFICATION_SERVICE)
162
+
163
+ # importance= autoclass('android.app.NotificationManager').IMPORTANCE_HIGH # also works #NotificationManager.IMPORTANCE_DEFAULT
164
+ importance= NotificationManagerCompat.IMPORTANCE_HIGH #autoclass('android.app.NotificationManager').IMPORTANCE_HIGH also works #NotificationManager.IMPORTANCE_DEFAULT
165
+
166
+ # Notification Channel (Required for Android 8.0+)
167
+ if BuildVersion.SDK_INT >= 26:
168
+ channel = NotificationChannel(channel_id, channel_name,importance)
169
+ notification_manager.createNotificationChannel(channel)
170
+
171
+ # Build the notification
172
+ builder = NotificationCompatBuilder(context, channel_id)
173
+ builder.setContentTitle(title)
174
+ builder.setContentText(message)
175
+ insert_app_icon(builder,custom_app_icon_path)
176
+ builder.setDefaults(NotificationCompat.DEFAULT_ALL)
177
+ builder.setPriority(NotificationCompat.PRIORITY_HIGH)
178
+
179
+ if img_path:
180
+ print('android_notify- img_path arg deprecated use "large_icon_path or big_picture_path or custom_app_icon_path" instead')
181
+ if style:
182
+ print('android_notify- "style" arg deprecated use args "big_picture_path", "large_icon_path", "big_text", "lines" instead')
183
+
184
+ big_picture = None
185
+ if big_picture_path:
186
+ try:
187
+ big_picture = get_image_uri(big_picture_path)
188
+ except FileNotFoundError as e:
189
+ print('android_notify- Error Getting Uri for big_picture_path: ',e)
190
+
191
+ large_icon = None
192
+ if large_icon_path:
193
+ try:
194
+ large_icon = get_image_uri(large_icon_path)
195
+ except FileNotFoundError as e:
196
+ print('android_notify- Error Getting Uri for large_icon_path: ',e)
197
+
198
+
199
+ # Apply notification styles
200
+ try:
201
+ if big_text:
202
+ big_text_style = NotificationCompatBigTextStyle()
203
+ big_text_style.bigText(big_text)
204
+ builder.setStyle(big_text_style)
205
+
206
+ elif lines:
207
+ inbox_style = NotificationCompatInboxStyle()
208
+ for line in lines.split("\n"):
209
+ inbox_style.addLine(line)
210
+ builder.setStyle(inbox_style)
211
+
212
+ if large_icon:
213
+ bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(large_icon))
214
+ builder.setLargeIcon(bitmap)
215
+
216
+ if big_picture:
217
+ bitmap = BitmapFactory.decodeStream(context.getContentResolver().openInputStream(big_picture))
218
+ big_picture_style = NotificationCompatBigPictureStyle().bigPicture(bitmap)
219
+ builder.setStyle(big_picture_style)
220
+
221
+ except Exception as e:
222
+ print('android_notify- Error Failed Adding Style: ',e)
223
+ # Display the notification
224
+ notification_id = random.randint(0, 100)
225
+ notification_manager.notify(notification_id, builder.build())
226
+ return notification_id
227
+
android_notify/styles.py CHANGED
@@ -1,22 +1,25 @@
1
- """Contains Safe way to call Styles"""
2
-
3
- class NotificationStyles:
4
- """ Safely Adding Styles"""
5
- DEFAULT = "simple"
6
-
7
- PROGRESS = "progress"
8
- INBOX = "inbox"
9
-
10
- # v1.59+
11
- # Deprecated
12
- # setBigText == Notification(...,big_picture_path="...",style=NotificationStyles.BIG_TEXT)
13
- # setLargeIcon == Notification(...,large_icon_path="...",style=NotificationStyles.LARGE_ICON)
14
- # setBigPicture == Notification(...,body="...",style=NotificationStyles.BIG_PICTURE)
15
- # Use .refresh to apply any new changes after .send
16
- BIG_TEXT = "big_text"
17
- LARGE_ICON = "large_icon"
18
- BIG_PICTURE = "big_picture"
19
- BOTH_IMGS = "both_imgs"
20
-
21
- # MESSAGING = "messaging" # TODO
22
- # CUSTOM = "custom" # TODO
1
+ """Contains Safe way to call Styles"""
2
+
3
+ class NotificationStyles:
4
+ """ Safely Adding Styles"""
5
+
6
+ # v1.59+
7
+ # Deprecated
8
+ # setBigText == Notification(...,big_picture_path="...",style=NotificationStyles.BIG_TEXT)
9
+ # setLargeIcon == Notification(...,large_icon_path="...",style=NotificationStyles.LARGE_ICON)
10
+ # setBigPicture == Notification(...,body="...",style=NotificationStyles.BIG_PICTURE)
11
+ # setLines == Notification(...,lines_txt="...",style=NotificationStyles.INBOX)
12
+ # Set progress_current_value and progress_max_value for progress style
13
+
14
+ # Use .refresh to apply any new changes after .send
15
+
16
+ DEFAULT = "simple"
17
+ PROGRESS = "progress"
18
+ INBOX = "inbox"
19
+ BIG_TEXT = "big_text"
20
+ LARGE_ICON = "large_icon"
21
+ BIG_PICTURE = "big_picture"
22
+ BOTH_IMGS = "both_imgs"
23
+
24
+ # MESSAGING = "messaging" # TODO
25
+ # CUSTOM = "custom" # TODO v1.60