flet-android-background 0.0.2__tar.gz → 0.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (15) hide show
  1. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/PKG-INFO +8 -9
  2. flet_android_background-0.0.3/README.md +18 -0
  3. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/pyproject.toml +1 -1
  4. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/src/flet_android_background/__init__.py +15 -2
  5. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/src/flet_android_background/service.py +8 -2
  6. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/src/flutter/flet_android_background/android/src/main/AndroidManifest.xml +1 -0
  7. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/src/flutter/flet_android_background/android/src/main/java/dev/alexstoica/background/BackgroundPlugin.java +2 -1
  8. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/src/flutter/flet_android_background/android/src/main/java/dev/alexstoica/background/TaskService.java +19 -0
  9. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/src/flutter/flet_android_background/pubspec.yaml +1 -1
  10. flet_android_background-0.0.2/README.md +0 -19
  11. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/.gitignore +0 -0
  12. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/LICENSE +0 -0
  13. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/src/flet_android_background/android.py +0 -0
  14. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/src/flutter/flet_android_background/android/build.gradle +0 -0
  15. {flet_android_background-0.0.2 → flet_android_background-0.0.3}/src/flutter/flet_android_background/lib/flet_android_background.dart +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flet-android-background
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: Experimental foreground tasks for Flet on Android
5
5
  Project-URL: Homepage, https://github.com/alex-stoica/flet-android-background
6
6
  Project-URL: Repository, https://github.com/alex-stoica/flet-android-background
@@ -15,14 +15,14 @@ Description-Content-Type: text/markdown
15
15
 
16
16
  # flet-android-background
17
17
 
18
- Experimental Flet Android tasks; one owns the foreground service.
19
- Locking permits continued execution; Android restrictions still apply.
20
- Dismissal or runtime loss stops the service. Process death has no recovery.
18
+ Experimental; no process-death recovery. Pip install.
21
19
 
22
- Install the wheel with pip. Add `BackgroundTask` to your Flet app, then
23
- `await task.start(work)` or `await task.stop()`.
20
+ Create `BackgroundTask` per page; set `page.on_close = task.on_session_close`.
21
+ Use `await task.start(work, enable_wifi_lock=True)` and `await task.stop()`.
22
+ WifiLock: default off; released on exit. Android 14+: foreground/screen-on only;
23
+ Doze applies. Bundles `WAKE_LOCK`; no CPU lock.
24
24
 
25
- Before building the generated Flutter project:
25
+ Before building:
26
26
 
27
27
  ```python
28
28
  from flet_android_background.android import configure_android_project
@@ -30,5 +30,4 @@ from flet_android_background.android import configure_android_project
30
30
  configure_android_project(path, service_type="dataSync")
31
31
  ```
32
32
 
33
- Supported types: `dataSync`, `shortService`, `specialUse`. The latter requires
34
- an app-specific `subtype` explanation. Android time limits apply.
33
+ Types: `dataSync`, `shortService`, `specialUse` (requires `subtype`). Time limits apply.
@@ -0,0 +1,18 @@
1
+ # flet-android-background
2
+
3
+ Experimental; no process-death recovery. Pip install.
4
+
5
+ Create `BackgroundTask` per page; set `page.on_close = task.on_session_close`.
6
+ Use `await task.start(work, enable_wifi_lock=True)` and `await task.stop()`.
7
+ WifiLock: default off; released on exit. Android 14+: foreground/screen-on only;
8
+ Doze applies. Bundles `WAKE_LOCK`; no CPU lock.
9
+
10
+ Before building:
11
+
12
+ ```python
13
+ from flet_android_background.android import configure_android_project
14
+
15
+ configure_android_project(path, service_type="dataSync")
16
+ ```
17
+
18
+ Types: `dataSync`, `shortService`, `specialUse` (requires `subtype`). Time limits apply.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "flet-android-background"
3
- version = "0.0.2"
3
+ version = "0.0.3"
4
4
  description = "Experimental foreground tasks for Flet on Android"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -16,6 +16,7 @@ class BackgroundTask:
16
16
  self._task: asyncio.Task[None] | None = None
17
17
  self._work: asyncio.Task[None] | None = None
18
18
  self._lock = asyncio.Lock()
19
+ self._session_closed = False
19
20
 
20
21
  @property
21
22
  def running(self) -> bool:
@@ -25,6 +26,7 @@ class BackgroundTask:
25
26
  **notification) -> bool:
26
27
  """Start once after notification permission; duplicates return False."""
27
28
  async with self._lock:
29
+ self._check_session()
28
30
  if self.running:
29
31
  return False
30
32
  self.error = None
@@ -35,6 +37,7 @@ class BackgroundTask:
35
37
  self._task = asyncio.create_task(self._rollback(starting))
36
38
  await asyncio.shield(self._task)
37
39
  raise
40
+ self._check_session()
38
41
  if failure is not None:
39
42
  raise failure
40
43
  self._work = asyncio.create_task(self._invoke(work))
@@ -53,7 +56,7 @@ class BackgroundTask:
53
56
  async def _rollback(self, starting):
54
57
  try:
55
58
  self.error = await starting
56
- if self.error is None:
59
+ if self.error is None and not self._session_closed:
57
60
  await self.service.stop_foreground_service()
58
61
  except Exception as exc:
59
62
  self.error = exc
@@ -73,7 +76,8 @@ class BackgroundTask:
73
76
  self.error = self.error or exc
74
77
  finally:
75
78
  try:
76
- await self.service.stop_foreground_service()
79
+ if not self._session_closed:
80
+ await self.service.stop_foreground_service()
77
81
  except Exception as exc:
78
82
  self.error = self.error or exc
79
83
 
@@ -85,6 +89,15 @@ class BackgroundTask:
85
89
  self._work.cancel()
86
90
  await asyncio.shield(self._task)
87
91
 
92
+ def _check_session(self):
93
+ if self._session_closed:
94
+ raise RuntimeError("Flet session closed; create a new BackgroundTask")
95
+
96
+ async def on_session_close(self, event=None):
97
+ """Cancel Python work after session loss; native teardown stops the service."""
98
+ self._session_closed = True
99
+ await self.stop()
100
+
88
101
  async def _stopped(self, event):
89
102
  async with self._lock:
90
103
  if event.data == self.service._owner and self.running:
@@ -16,10 +16,16 @@ class ForegroundService(ft.Service):
16
16
  return await self._call("permission")
17
17
 
18
18
  async def start_foreground_service(self, *, notification_id=1,
19
- title="Background task", body="Running"):
19
+ title="Background task", body="Running",
20
+ enable_wifi_lock: bool = False):
20
21
  if notification_id <= 0:
21
22
  raise ValueError("notification_id must be positive")
22
- self._owner = await self._call("start", id=notification_id, title=title, body=body)
23
+ if not isinstance(enable_wifi_lock, bool):
24
+ raise TypeError("enable_wifi_lock must be a bool")
25
+ self._owner = await self._call(
26
+ "start", id=notification_id, title=title, body=body,
27
+ enable_wifi_lock=enable_wifi_lock,
28
+ )
23
29
 
24
30
  async def stop_foreground_service(self):
25
31
  await self._call("stop")
@@ -1,6 +1,7 @@
1
1
  <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
2
  <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
3
3
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
4
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
4
5
  <application>
5
6
  <service android:name="dev.alexstoica.background.TaskService"
6
7
  android:exported="false" />
@@ -53,7 +53,8 @@ public class BackgroundPlugin implements FlutterPlugin, ActivityAware,
53
53
  Intent intent = new Intent(context, TaskService.class)
54
54
  .putExtra("id", ((Number) call.argument("id")).intValue())
55
55
  .putExtra("title", (String) call.argument("title"))
56
- .putExtra("body", (String) call.argument("body"));
56
+ .putExtra("body", (String) call.argument("body"))
57
+ .putExtra("enable_wifi_lock", Boolean.TRUE.equals(call.argument("enable_wifi_lock")));
57
58
  token = call.argument("owner");
58
59
  if (token == null) throw new IllegalArgumentException("Missing service owner");
59
60
  TaskService.owner = this;
@@ -7,11 +7,13 @@ import android.app.PendingIntent;
7
7
  import android.app.Service;
8
8
  import android.content.Intent;
9
9
  import android.os.Build;
10
+ import android.net.wifi.WifiManager;
10
11
  import android.os.IBinder;
11
12
 
12
13
  public class TaskService extends Service {
13
14
  static BackgroundPlugin owner;
14
15
  private static final String CHANNEL = "python_background";
16
+ private WifiManager.WifiLock wifiLock;
15
17
 
16
18
  @Override public int onStartCommand(Intent intent, int flags, int startId) {
17
19
  if (owner == null || intent == null || "stop".equals(intent.getAction())) {
@@ -38,14 +40,30 @@ public class TaskService extends Service {
38
40
  if (launch != null) builder.setContentIntent(PendingIntent.getActivity(
39
41
  this, 0, launch, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT));
40
42
  startForeground(intent.getIntExtra("id", 1), builder.build());
43
+ if (intent.getBooleanExtra("enable_wifi_lock", false) && wifiLock == null) {
44
+ WifiManager wifi = getApplicationContext().getSystemService(WifiManager.class);
45
+ if (wifi == null) throw new IllegalStateException("Wi-Fi service unavailable");
46
+ wifiLock = wifi.createWifiLock(
47
+ WifiManager.WIFI_MODE_FULL_HIGH_PERF, "flet_android_background:wifi");
48
+ wifiLock.setReferenceCounted(false);
49
+ wifiLock.acquire();
50
+ }
41
51
  } catch (Exception error) {
42
52
  failure = error;
53
+ releaseWifiLock();
43
54
  stopSelf();
44
55
  }
45
56
  owner.onStarted(failure);
46
57
  return START_NOT_STICKY;
47
58
  }
48
59
 
60
+ private void releaseWifiLock() {
61
+ if (wifiLock != null) {
62
+ if (wifiLock.isHeld()) wifiLock.release();
63
+ wifiLock = null;
64
+ }
65
+ }
66
+
49
67
  @Override public void onTaskRemoved(Intent intent) { stopSelf(); }
50
68
  @Override public void onTimeout(int startId) { stopSelf(); }
51
69
  @Override public void onTimeout(int startId, int type) { stopSelf(); }
@@ -53,6 +71,7 @@ public class TaskService extends Service {
53
71
  @Override public void onDestroy() {
54
72
  BackgroundPlugin previous = owner;
55
73
  owner = null;
74
+ releaseWifiLock();
56
75
  stopForeground(STOP_FOREGROUND_REMOVE);
57
76
  if (previous != null) previous.onStopped();
58
77
  super.onDestroy();
@@ -1,6 +1,6 @@
1
1
  name: flet_android_background
2
2
  description: Foreground task lifecycle for Flet Android apps
3
- version: 0.0.2
3
+ version: 0.0.3
4
4
  publish_to: none
5
5
  environment:
6
6
  sdk: '>=3.11.0 <4.0.0'
@@ -1,19 +0,0 @@
1
- # flet-android-background
2
-
3
- Experimental Flet Android tasks; one owns the foreground service.
4
- Locking permits continued execution; Android restrictions still apply.
5
- Dismissal or runtime loss stops the service. Process death has no recovery.
6
-
7
- Install the wheel with pip. Add `BackgroundTask` to your Flet app, then
8
- `await task.start(work)` or `await task.stop()`.
9
-
10
- Before building the generated Flutter project:
11
-
12
- ```python
13
- from flet_android_background.android import configure_android_project
14
-
15
- configure_android_project(path, service_type="dataSync")
16
- ```
17
-
18
- Supported types: `dataSync`, `shortService`, `specialUse`. The latter requires
19
- an app-specific `subtype` explanation. Android time limits apply.