android-notify 1.24.3__py3-none-any.whl → 1.30__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.

Potentially problematic release.


This version of android-notify might be problematic. Click here for more details.

@@ -1,345 +0,0 @@
1
- from jnius import autoclass, cast
2
- import random
3
- import os
4
- from enum import Enum
5
- from typing import Optional, List, Union
6
- from dataclasses import dataclass
7
-
8
- class NotificationImportance(Enum):
9
- MIN = 1
10
- LOW = 2
11
- DEFAULT = 3
12
- HIGH = 4
13
-
14
- class NotificationPriority(Enum):
15
- MIN = -2
16
- LOW = -1
17
- DEFAULT = 0
18
- HIGH = 1
19
- MAX = 2
20
-
21
- class NotificationStyle(Enum):
22
- DEFAULT = "default"
23
- BIG_TEXT = "big_text"
24
- BIG_PICTURE = "big_picture"
25
- INBOX = "inbox"
26
- MESSAGING = "messaging"
27
-
28
- @dataclass
29
- class NotificationAction:
30
- name: str
31
- intent: str
32
- icon: Optional[int] = None
33
-
34
- class AndroidNotificationSystem:
35
- """Singleton class to handle Android-specific initialization and classes"""
36
- _instance = None
37
- _initialized = False
38
-
39
- def __new__(cls):
40
- if cls._instance is None:
41
- cls._instance = super(AndroidNotificationSystem, cls).__new__(cls)
42
- return cls._instance
43
-
44
- def __init__(self):
45
- if not self._initialized:
46
- self._initialize_android_classes()
47
- self._initialized = True
48
-
49
- def _initialize_android_classes(self):
50
- try:
51
- # Core Android classes
52
- self.PythonActivity = autoclass('org.kivy.android.PythonActivity')
53
- self.NotificationChannel = autoclass('android.app.NotificationChannel')
54
- self.String = autoclass('java.lang.String')
55
- self.Intent = autoclass('android.content.Intent')
56
- self.PendingIntent = autoclass('android.app.PendingIntent')
57
- self.Context = self.PythonActivity.mActivity
58
- self.BitmapFactory = autoclass('android.graphics.BitmapFactory')
59
- self.BuildVersion = autoclass('android.os.Build$VERSION')
60
-
61
- # Notification specific classes
62
- self.NotificationManagerCompat = autoclass('androidx.core.app.NotificationManagerCompat')
63
- self.NotificationCompat = autoclass('androidx.core.app.NotificationCompat')
64
- self.NotificationBuilder = autoclass('androidx.core.app.NotificationCompat$Builder')
65
- self.BigTextStyle = autoclass('androidx.core.app.NotificationCompat$BigTextStyle')
66
- self.BigPictureStyle = autoclass('androidx.core.app.NotificationCompat$BigPictureStyle')
67
- self.InboxStyle = autoclass('androidx.core.app.NotificationCompat$InboxStyle')
68
- self.MessagingStyle = autoclass('androidx.core.app.NotificationCompat$MessagingStyle')
69
-
70
- self.is_initialized = True
71
- except Exception as e:
72
- raise ImportError(
73
- "Failed to initialize Android classes. Ensure you have the following in buildozer.spec:\n"
74
- "android.gradle_dependencies = androidx.core:core-ktx:1.15.0, androidx.core:core:1.6.0\n"
75
- "android.enable_androidx = True\n"
76
- "android.permissions = POST_NOTIFICATIONS"
77
- ) from e
78
-
79
- class NotificationChannel:
80
- def __init__(
81
- self,
82
- channel_id: str,
83
- name: str,
84
- importance: NotificationImportance = NotificationImportance.DEFAULT,
85
- description: Optional[str] = None,
86
- enable_lights: bool = True,
87
- enable_vibration: bool = True
88
- ):
89
- self.android = AndroidNotificationSystem()
90
- self.channel_id = channel_id
91
- self.name = name
92
-
93
- if self.android.BuildVersion.SDK_INT >= 26:
94
- channel = self.android.NotificationChannel(
95
- channel_id,
96
- name,
97
- importance.value
98
- )
99
- if description:
100
- channel.setDescription(description)
101
- channel.enableLights(enable_lights)
102
- channel.enableVibration(enable_vibration)
103
-
104
- self.android.Context.getSystemService(
105
- self.android.Context.NOTIFICATION_SERVICE
106
- ).createNotificationChannel(channel)
107
-
108
- class EnhancedNotificationManager:
109
- """Enhanced notification manager with more features and better organization"""
110
-
111
- _notification_ids = set()
112
-
113
- def __init__(
114
- self,
115
- channel_id: str,
116
- channel_name: str,
117
- importance: NotificationImportance = NotificationImportance.HIGH,
118
- group_key: Optional[str] = None
119
- ):
120
- self.android = AndroidNotificationSystem()
121
- self.channel = NotificationChannel(channel_id, channel_name, importance)
122
- self.builder = self.android.NotificationBuilder(
123
- self.android.Context,
124
- channel_id
125
- )
126
- self.notification_id = self._generate_unique_id()
127
- self.group_key = group_key
128
-
129
- if group_key:
130
- self.builder.setGroup(group_key)
131
-
132
- def _generate_unique_id(self) -> int:
133
- while (notification_id := random.randint(1, 10000)) in self._notification_ids:
134
- continue
135
- self._notification_ids.add(notification_id)
136
- return notification_id
137
-
138
- def set_content(
139
- self,
140
- title: str,
141
- message: str,
142
- style: NotificationStyle = NotificationStyle.DEFAULT,
143
- style_content: Optional[Union[str, str]] = None,
144
- image_path: Optional[str] = None
145
- ):
146
- """Set notification content with enhanced styling options"""
147
- self.builder.setContentTitle(title)
148
- self.builder.setContentText(message)
149
-
150
- if style == NotificationStyle.BIG_TEXT:
151
- big_text = style_content or message
152
- self.builder.setStyle(
153
- self.android.BigTextStyle().bigText(big_text)
154
- )
155
- elif style == NotificationStyle.BIG_PICTURE and image_path:
156
- bitmap = self._load_image(image_path)
157
- if bitmap:
158
- self.builder.setStyle(
159
- self.android.BigPictureStyle()
160
- .bigPicture(bitmap)
161
- .setBigContentTitle(title)
162
- )
163
- elif style == NotificationStyle.INBOX and isinstance(style_content, list):
164
- inbox_style = self.android.InboxStyle()
165
- for line in style_content:
166
- inbox_style.addLine(line)
167
- self.builder.setStyle(inbox_style)
168
- elif style == NotificationStyle.MESSAGING:
169
- messaging_style = self.android.MessagingStyle("User")
170
- if isinstance(style_content, list):
171
- for msg in style_content:
172
- messaging_style.addMessage(msg, 0, "Sender")
173
- self.builder.setStyle(messaging_style)
174
-
175
- def add_actions(self, actions: List[NotificationAction]):
176
- """Add multiple actions (buttons) to the notification"""
177
- for action in actions:
178
- intent = self.android.Intent(
179
- self.android.Context,
180
- self.android.PythonActivity
181
- )
182
- intent.setAction(action.intent)
183
-
184
- pending_intent = self.android.PendingIntent.getActivity(
185
- self.android.Context,
186
- random.randint(0, 10000), # Unique request code
187
- intent,
188
- self.android.PendingIntent.FLAG_IMMUTABLE
189
- )
190
-
191
- icon = action.icon or self.android.Context.getApplicationInfo().icon
192
- action_text = cast('java.lang.CharSequence',
193
- self.android.String(action.name))
194
-
195
- self.builder.addAction(icon, action_text, pending_intent)
196
-
197
- def set_icons(
198
- self,
199
- small_icon_path: Optional[str] = None,
200
- large_icon_path: Optional[str] = None
201
- ):
202
- """Set both small and large icons"""
203
- if small_icon_path:
204
- small_icon = self._load_image(small_icon_path)
205
- if small_icon:
206
- self.builder.setSmallIcon(small_icon)
207
- else:
208
- self.builder.setSmallIcon(
209
- self.android.Context.getApplicationInfo().icon
210
- )
211
-
212
- if large_icon_path:
213
- large_icon = self._load_image(large_icon_path)
214
- if large_icon:
215
- self.builder.setLargeIcon(large_icon)
216
-
217
- def _load_image(self, image_path: str):
218
- """Load image from app storage with error handling"""
219
- try:
220
- uri = self.__get_image_uri(image_path)
221
- return self.android.BitmapFactory.decodeStream(
222
- self.android.Context.getContentResolver().openInputStream(uri)
223
- )
224
- except Exception as e:
225
- print(f"Failed to load image: {e}")
226
- return None
227
-
228
- def __get_image_uri(self, relative_path: str):
229
- """Get URI for image file"""
230
- from android.storage import app_storage_path # type: ignore
231
-
232
- output_path = os.path.join(
233
- app_storage_path(),
234
- 'app',
235
- relative_path
236
- )
237
- if not os.path.exists(output_path):
238
- raise FileNotFoundError(
239
- f"Image not found at path: {output_path}"
240
- )
241
-
242
- Uri = autoclass('android.net.Uri')
243
- return Uri.parse(f"file://{output_path}")
244
-
245
- def set_priority(self, priority: NotificationPriority):
246
- """Set notification priority"""
247
- self.builder.setPriority(priority.value)
248
-
249
- def set_ongoing(self, ongoing: bool = True):
250
- """Set whether notification is ongoing"""
251
- self.builder.setOngoing(ongoing)
252
-
253
- def set_auto_cancel(self, auto_cancel: bool = True):
254
- """Set whether notification is automatically canceled on click"""
255
- self.builder.setAutoCancel(auto_cancel)
256
-
257
- def send(self) -> int:
258
- """Send the notification and return its ID"""
259
- notification_manager = self.android.Context.getSystemService(
260
- self.android.Context.NOTIFICATION_SERVICE
261
- )
262
- notification_manager.notify(
263
- self.notification_id,
264
- self.builder.build()
265
- )
266
- return self.notification_id
267
-
268
- def update(
269
- self,
270
- title: Optional[str] = None,
271
- message: Optional[str] = None,
272
- progress: Optional[tuple] = None
273
- ):
274
- """Update existing notification"""
275
- if title:
276
- self.builder.setContentTitle(title)
277
- if message:
278
- self.builder.setContentText(message)
279
- if progress:
280
- current, max_value = progress
281
- self.builder.setProgress(max_value, current, False)
282
-
283
- self.send()
284
-
285
- def cancel(self):
286
- """Cancel this notification"""
287
- notification_manager = self.android.Context.getSystemService(
288
- self.android.Context.NOTIFICATION_SERVICE
289
- )
290
- notification_manager.cancel(self.notification_id)
291
- self._notification_ids.remove(self.notification_id)
292
-
293
- @classmethod
294
- def cancel_all(cls):
295
- """Cancel all notifications"""
296
- android = AndroidNotificationSystem()
297
- notification_manager = android.Context.getSystemService(
298
- android.Context.NOTIFICATION_SERVICE
299
- )
300
- notification_manager.cancelAll()
301
- cls._notification_ids.clear()
302
-
303
- # Example usage:
304
- def example_usage():
305
- # Create a notification
306
- notification = EnhancedNotificationManager(
307
- channel_id="messages",
308
- channel_name="Messages",
309
- importance=NotificationImportance.HIGH
310
- )
311
-
312
- # Set basic content
313
- notification.set_content(
314
- title="New Message",
315
- message="Hello World!",
316
- style=NotificationStyle.BIG_TEXT
317
- )
318
-
319
- # Add actions
320
- actions = [
321
- NotificationAction("Reply", "REPLY_ACTION"),
322
- NotificationAction("Delete", "DELETE_ACTION")
323
- ]
324
- notification.add_actions(actions)
325
-
326
- # Set icons
327
- notification.set_icons(
328
- large_icon_path="assets/imgs/profile.png"
329
- )
330
-
331
- # Configure behavior
332
- notification.set_priority(NotificationPriority.HIGH)
333
- notification.set_auto_cancel(True)
334
-
335
- # Send the notification
336
- notification_id = notification.send()
337
-
338
- # Later, update the notification
339
- notification.update(
340
- message="Updated message!",
341
- progress=(50, 100)
342
- )
343
-
344
- # Cancel when done
345
- notification.cancel()
@@ -1,298 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: android-notify
3
- Version: 1.24.3
4
- Summary: A Python package that simpilfies creating Android Post notifications using PyJNIus in Kivy apps.
5
- Home-page: https://github.com/fector101/android-notify
6
- Author: Fabian
7
- Author-email: fector101@yahoo.com
8
- License: MIT
9
- Project-URL: Documentation, https://github.com/fector101/android-notify/
10
- Project-URL: Source, https://github.com/fector101/android-notify
11
- Project-URL: Tracker, https://github.com/fector101/android-notify/issues
12
- Project-URL: Funding, https://www.buymeacoffee.com/fector101
13
- Keywords: android,notifications,kivy,mobile,post notifications,pyjnius,android notifications,kivy notifications,python android,mobile development
14
- Classifier: Programming Language :: Python :: 3
15
- Classifier: License :: OSI Approved :: MIT License
16
- Classifier: Operating System :: Android
17
- Classifier: Development Status :: 5 - Production/Stable
18
- Classifier: Intended Audience :: Developers
19
- Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
- Requires-Python: >=3.6
21
- Description-Content-Type: text/markdown
22
- Requires-Dist: kivy>=2.0.0
23
- Requires-Dist: pyjnius>=1.4.2
24
-
25
- # Android Notify
26
-
27
- `android_notify` is a Python module designed to simplify sending Android notifications using Kivy and Pyjnius. It supports multiple notification styles, including text, images, and inbox layouts.
28
-
29
- ## Features
30
-
31
- - Send Android notifications with custom titles and messages.
32
- - Support for multiple notification styles:
33
- - Big Text
34
- - Big Picture
35
- - Large Icon
36
- - Inbox
37
- - Supports including images in notifications.
38
- - Compatible with Android 8.0+ (Notification Channels).
39
- - Customizable notification channels.
40
-
41
- ## Installation
42
-
43
- This package is available on PyPI and can be installed via pip:
44
-
45
- ```bash
46
- pip install android-notify
47
- ```
48
-
49
- ## **Dependencies**
50
-
51
- **Prerequisites:**
52
-
53
- - Buildozer
54
- - Kivy
55
-
56
- In your **`buildozer.spec`** file, ensure you include the following:
57
-
58
- ```ini
59
- # Add pyjnius so it's packaged with the build
60
- requirements = python3, kivy, pyjnius, android-notify
61
-
62
- # Add permission for notifications
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
- ```
69
-
70
- ---
71
-
72
- ### Example Notification
73
-
74
- #### Basic Notification
75
-
76
- ```python
77
- from android_notify import send_notification
78
-
79
- # Send a basic notification
80
- send_notification("Hello", "This is a basic notification.")
81
- ```
82
-
83
- **Example Image:**
84
- ![basic notification img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/basicnoti.jpg)
85
- #### Notification with an Image (Big Picture Style)
86
-
87
- ```python
88
- # Send a notification with an image
89
- send_notification(
90
- title='Picture Alert!',
91
- message='This notification includes an image.',
92
- style='big_picture',
93
- img_path='assets/imgs/icon.png'
94
- )
95
- ```
96
-
97
- **Example Image:**
98
- ![big_picture img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/bigpicturenoti.jpg)
99
- #### Notification with an Image (Large Icon Style)
100
-
101
- ```python
102
- # Send a notification with Large Icon
103
- send_notification(
104
- title='Completed download',
105
- message='profile.jpg',
106
- style='large_icon',
107
- img_path='assets/imgs/icon.png'
108
- )
109
- ```
110
-
111
- **Example Image:**
112
- ![large_icon img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/large_icon.jpg)
113
-
114
- #### Inbox Notification Style
115
-
116
- ```python
117
- # Send a notification with inbox style
118
- send_notification(
119
- title='Inbox Notification',
120
- message='Line 1\nLine 2\nLine 3',
121
- style='inbox'
122
- )
123
- ```
124
-
125
- **Example Image:**
126
- ![Inbox Notification sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/inboxnoti.jpg)
127
-
128
- #### Big Text Notification
129
-
130
- - (This will default to normal text if big text unsupported on device)
131
-
132
- ```python
133
- # Send a Big Text notification
134
- send_notification(
135
- title='Hello!',
136
- message='This is a sample notification.',
137
- style='big_text'
138
- )
139
- ```
140
- <!--
141
- **Example Image:**
142
- ![Big Text Notification sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/big_text.jpg) -->
143
-
144
- ---
145
-
146
- ### Advanced Usage
147
-
148
- #### Channel Name (channel_name)
149
-
150
- - Can be found in App Settings where user can turn on/off specific Notifications
151
-
152
- ```python
153
- # if not specified Channel Name default's to "Default Channel"
154
- send_notification(
155
- title="Download finished"
156
- message="How to Catch a Fish.mp4"
157
- channel_name="Download Notifications"
158
- )
159
- ```
160
-
161
- **Sample Image:**
162
- ![channels img sample](https://raw.githubusercontent.com/Fector101/android_notify/main/docs/imgs/channel_name.jpg)
163
-
164
- #### Channel Name (channel_id)
165
-
166
- You can customize notification channels for different types of notifications.(In later version channel_id will be used to reference notification)
167
-
168
- ```python
169
- send_notification(
170
- title='Custom Channel Notification',
171
- message='This uses a custom notification channel.',
172
- channel_id='custom_channel'
173
- )
174
- ```
175
-
176
- ---
177
-
178
- ### **Assist**
179
-
180
- - How to Copy image to app folder
181
-
182
- ```python
183
- import shutil,os # These modules come packaged with python
184
- from android.storage import app_storage_path # type: ignore -- This works only on android
185
-
186
- app_path = os.path.join(app_storage_path(),'app')
187
- image_path= "/storage/emulated/0/Download/profile.png"
188
-
189
- shutil.copy(image_path, os.path.join(app_path, "profile.png"))
190
- ```
191
-
192
- - Avoiding Human Error when using different notification styles
193
-
194
- ```python
195
- from android_notify import send_notification, NotificationStyles
196
- send_notification(
197
- title='Picture Alert!',
198
- message='This notification includes an image.',
199
- img_path='assets/imgs/icon.png'
200
- style=NotificationStyles.BIG_PICTURE,
201
- )
202
- ```
203
-
204
- ---
205
-
206
- ### **Functions Reference**
207
-
208
- ### 1. `asks_permission_if_needed()`
209
-
210
- **Description:**
211
-
212
- - Checks if notification permissions are granted and requests them if missing.
213
-
214
- **Usage:**
215
-
216
- ```python
217
- asks_permission_if_needed()
218
- ```
219
-
220
- ---
221
-
222
- ### 2. `get_image_uri(relative_path)`
223
-
224
- **Description:**
225
-
226
- - Resolves the absolute URI for an image in the app's storage.
227
-
228
- **Parameters:**
229
-
230
- - `relative_path` *(str)*: Path to the image (e.g., `assets/imgs/icon.png`).
231
-
232
- **Returns:**
233
-
234
- - `Uri`: Android URI object for the image.
235
-
236
- **Usage:**
237
-
238
- ```python
239
- uri = get_image_uri('assets/imgs/icon.png')
240
- ```
241
-
242
- ---
243
-
244
- ### 3. `send_notification(title, message, style=None, img_path=None, channel_id='default_channel')`
245
-
246
- **Description:**
247
-
248
- - Sends an Android notification with optional styles and images.
249
-
250
- **Parameters:**
251
-
252
- - `title` *(str)*: Notification title.
253
- - `message` *(str)*: Notification message.
254
- - `style` *(str, optional)*: Notification style (`big_text`, `big_picture`, `inbox`, `large_icon`).
255
- - `img_path` *(str, optional)*: Path to the image resource.(for `big_picture` or `large_icon` styles).
256
- - `channel_id` *(str, optional)*: Notification channel ID.
257
-
258
- Returns - notification id
259
-
260
- ## Contribution
261
-
262
- Feel free to open issues or submit pull requests for improvements!
263
-
264
- ## 🐛 Reporting Issues
265
-
266
- Found a bug? Please open an issue on our [GitHub Issues](https://github.com/Fector101/android_notify/issues) page.
267
-
268
- ## Author
269
-
270
- - Fabian - <fector101@yahoo.com>
271
- - GitHub: <https://github.com/Fector101/android_notify>
272
- - Twitter: <https://x.com/CodewithFabian> -- 😊 I'm sure to answer
273
-
274
- For feedback or contributions, feel free to reach out!
275
-
276
- ---
277
-
278
- ## ☕ Support the Project
279
-
280
- If you find this project helpful, consider buying me a coffee! Or Giving it a star on 🌟 [GitHub](https://github.com/Fector101/android_notify/) Your support helps maintain and improve the project.
281
-
282
- <a href="https://www.buymeacoffee.com/fector101" target="_blank">
283
- <img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="60">
284
- </a>
285
-
286
- ---
287
-
288
- ## Acknowledgments
289
-
290
- - This Project was "Made For Android" and thoroughly "Tested by" the [Laner Project](https://github.com/Fector101/Laner/) - Laner is an application that creates a secure connection between your PC and Phone to Transfer Files Wirelessly.
291
- - Thanks to the Kivy and Pyjnius communities for their support.
292
-
293
- ---
294
-
295
- ## 🌐 **Links**
296
-
297
- - **PyPI:** [android-notify on PyPI](https://pypi.org/project/android-notify/)
298
- - **GitHub:** [Source Code Repository](https://github.com/Fector101/android_notify/)
@@ -1,10 +0,0 @@
1
- android_notify/__init__.py,sha256=37Y04a1PbxeQlOpruIUhr7KibSZRfrV9uvSeelCNO58,261
2
- android_notify/__main__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- android_notify/_dev.py,sha256=zGHGQu8Tv2RBtxiPDdIR0H-TLbzDocktIu_d78IgQgU,5207
4
- android_notify/advanced_dev.py,sha256=sUY3OjTC3arvtqOKtDpor14QSTRrwsuMI9susyfXwZo,12065
5
- android_notify/core.py,sha256=JkI5uiJof_gbuJJQ6YqgwWBTOWkhSKsGtVR8A9IIUN4,6024
6
- android_notify/styles.py,sha256=P_8sAqb3Hbf_vbhqSoCVjKeqJ05Fr_CksO-HX5pj8pU,134
7
- android_notify-1.24.3.dist-info/METADATA,sha256=LkrobjLyxHY2WwTNM7kfAQrmw-iRxsUlkN1xLan2Pro,8247
8
- android_notify-1.24.3.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
9
- android_notify-1.24.3.dist-info/top_level.txt,sha256=IR1ONMrRSRINZpWn2X0dL5gbWwWINsK7PW8Jy2p4fU8,15
10
- android_notify-1.24.3.dist-info/RECORD,,