LCOV - code coverage report
Current view: top level - src - constraints.dart Coverage Total Hit
Test: lcov.info Lines: 86.0 % 121 104
Test Date: 2026-04-30 18:23:23 Functions: - 0 0

            Line data    Source code
       1              : import 'package:flutter/foundation.dart';
       2              : 
       3              : /// Backoff policy for retry behavior when task fails.
       4              : ///
       5              : /// **Android**: Determines retry behavior for failed WorkManager tasks.
       6              : /// **iOS**: Not applicable (manual retry required).
       7              : enum BackoffPolicy {
       8              :   /// Exponential backoff - Delay doubles after each retry.
       9              :   ///
      10              :   /// **Delay Pattern**: 30s, 60s, 120s, 240s, ...
      11              :   ///
      12              :   /// **Use Cases**: Network errors, server issues (gives server time to recover).
      13              :   exponential,
      14              : 
      15              :   /// Linear backoff - Constant delay between retries.
      16              :   ///
      17              :   /// **Delay Pattern**: 30s, 30s, 30s, 30s, ...
      18              :   ///
      19              :   /// **Use Cases**: Database locks, transient errors.
      20              :   linear,
      21              : }
      22              : 
      23              : /// Quality of Service (QoS) priority for task execution.
      24              : ///
      25              : /// **iOS**: Maps to DispatchQoS for task execution priority.
      26              : /// **Android**: Ignored (WorkManager handles priority automatically).
      27              : enum QoS {
      28              :   /// Low priority - User is not waiting.
      29              :   ///
      30              :   /// **Use Cases**: Prefetching, maintenance, non-urgent sync.
      31              :   utility,
      32              : 
      33              :   /// Default priority - Deferrable work.
      34              :   ///
      35              :   /// **Use Cases**: Most background tasks, indexing, cleanup.
      36              :   background,
      37              : 
      38              :   /// Important work - User may be waiting.
      39              :   ///
      40              :   /// **Use Cases**: Explicit user action, data refresh from user request.
      41              :   userInitiated,
      42              : 
      43              :   /// Critical work - User actively waiting.
      44              :   ///
      45              :   /// **Use Cases**: UI updates, immediate user-facing operations.
      46              :   /// **Note**: Avoid for background tasks (defeats purpose of background work).
      47              :   userInteractive,
      48              : }
      49              : 
      50              : /// iOS-specific behavior for exact time alarms.
      51              : ///
      52              : /// **Background**: iOS does not allow background code execution at exact times.
      53              : /// This enum provides transparency and control over how exact alarms are handled on iOS.
      54              : ///
      55              : /// **Android**: Always executes worker code (this setting is ignored).
      56              : enum ExactAlarmIOSBehavior {
      57              :   /// Show a local notification at the exact time (DEFAULT - Safe).
      58              :   ///
      59              :   /// **Guarantees**:
      60              :   /// - ✅ Notification appears at exact time (±seconds)
      61              :   /// - ✅ Works in Low Power Mode
      62              :   /// - ✅ Survives app termination
      63              :   ///
      64              :   /// **Use Cases**: Reminders, alarms, time-sensitive notifications.
      65              :   showNotification,
      66              : 
      67              :   /// Attempt background code execution (Best Effort - NOT GUARANTEED).
      68              :   ///
      69              :   /// **Limitations**:
      70              :   /// - ❌ NOT suitable for time-critical operations
      71              :   /// - ❌ Timing accuracy: ±minutes to ±hours
      72              :   /// - ❌ May not run in Low Power Mode
      73              :   ///
      74              :   /// **Use Cases**: Non-critical background sync with timing hint.
      75              :   attemptBackgroundRun,
      76              : 
      77              :   /// Throw exception immediately (Fail Fast - Development Safety).
      78              :   ///
      79              :   /// **Benefits**:
      80              :   /// - ✅ Immediate feedback during development
      81              :   /// - ✅ Prevents deploying code with wrong expectations
      82              :   /// - ✅ Forces platform-aware design
      83              :   ///
      84              :   /// **Use Cases**: Development/testing, critical operations that require exact timing.
      85              :   throwError,
      86              : }
      87              : 
      88              : /// System-level constraints for task execution (Android only).
      89              : ///
      90              : /// **New in KMP WorkManager 2.2.0+**: SystemConstraints provide a cleaner way to
      91              : /// specify system-level requirements. These replace the deprecated trigger-based
      92              : /// approach (TaskTrigger.batteryLow, etc.) and the individual boolean flags.
      93              : ///
      94              : /// **Platform Support**: Android only. iOS ignores these constraints.
      95              : ///
      96              : /// ## Basic Usage
      97              : ///
      98              : /// ```dart
      99              : /// await NativeWorkManager.enqueue(
     100              : ///   taskId: 'maintenance-task',
     101              : ///   trigger: TaskTrigger.oneTime(),
     102              : ///   worker: DartWorker(callbackId: 'cleanup'),
     103              : ///   constraints: Constraints(
     104              : ///     systemConstraints: {
     105              : ///       SystemConstraint.deviceIdle,  // Run when device is idle
     106              : ///       SystemConstraint.allowLowStorage,  // OK to run on low storage
     107              : ///     },
     108              : ///   ),
     109              : /// );
     110              : /// ```
     111              : ///
     112              : /// ## Constraint Types
     113              : ///
     114              : /// **Storage Constraints:**
     115              : /// - `allowLowStorage` - Task can run even when storage is low
     116              : /// - Default behavior: Task waits for sufficient storage
     117              : ///
     118              : /// **Battery Constraints:**
     119              : /// - `allowLowBattery` - Task can run even when battery is low
     120              : /// - `requireBatteryNotLow` - Task requires battery level to not be low
     121              : /// - Default behavior: No battery restriction
     122              : ///
     123              : /// **System State:**
     124              : /// - `deviceIdle` - Task requires device to be idle (screen off, no user interaction)
     125              : /// - Use for maintenance tasks that should not impact user experience
     126              : ///
     127              : /// ## Migration from Old API
     128              : ///
     129              : /// **Before (deprecated triggers):**
     130              : /// ```dart
     131              : /// // OLD - deprecated in v2.2.0
     132              : /// trigger: TaskTrigger.storageLow,  // or batteryLow, deviceIdle
     133              : /// ```
     134              : ///
     135              : /// **After (SystemConstraints):**
     136              : /// ```dart
     137              : /// // NEW - recommended approach
     138              : /// constraints: Constraints(
     139              : ///   systemConstraints: {SystemConstraint.allowLowStorage},
     140              : /// )
     141              : /// ```
     142              : ///
     143              : /// **Before (boolean flags):**
     144              : /// ```dart
     145              : /// // OLD - still works but less flexible
     146              : /// constraints: Constraints(
     147              : ///   requiresStorageNotLow: true,
     148              : ///   requiresBatteryNotLow: true,
     149              : ///   requiresDeviceIdle: true,
     150              : /// )
     151              : /// ```
     152              : ///
     153              : /// **After (SystemConstraints - more explicit):**
     154              : /// ```dart
     155              : /// // NEW - clearer intent
     156              : /// constraints: Constraints(
     157              : ///   systemConstraints: {
     158              : ///     SystemConstraint.deviceIdle,
     159              : ///     SystemConstraint.requireBatteryNotLow,
     160              : ///   },
     161              : /// )
     162              : /// ```
     163              : ///
     164              : /// ## Common Patterns
     165              : ///
     166              : /// **Maintenance Task (idle device, low priority):**
     167              : /// ```dart
     168              : /// Constraints(
     169              : ///   systemConstraints: {
     170              : ///     SystemConstraint.deviceIdle,
     171              : ///     SystemConstraint.allowLowStorage,
     172              : ///     SystemConstraint.allowLowBattery,
     173              : ///   },
     174              : ///   qos: QoS.utility,
     175              : /// )
     176              : /// ```
     177              : ///
     178              : /// **Critical Task (needs resources):**
     179              : /// ```dart
     180              : /// Constraints(
     181              : ///   systemConstraints: {
     182              : ///     SystemConstraint.requireBatteryNotLow,
     183              : ///   },
     184              : ///   requiresNetwork: true,
     185              : ///   requiresCharging: true,
     186              : /// )
     187              : /// ```
     188              : ///
     189              : /// **Background Sync (opportunistic):**
     190              : /// ```dart
     191              : /// Constraints(
     192              : ///   systemConstraints: {
     193              : ///     SystemConstraint.allowLowBattery,  // Run even on low battery
     194              : ///   },
     195              : ///   requiresNetwork: true,
     196              : /// )
     197              : /// ```
     198              : ///
     199              : /// ## Platform Behavior
     200              : ///
     201              : /// **Android:**
     202              : /// - Maps to WorkManager's SystemConstraint API
     203              : /// - Enforced by Android WorkManager
     204              : /// - Affects task scheduling and execution
     205              : ///
     206              : /// **iOS:**
     207              : /// - Ignored (not applicable to iOS background tasks)
     208              : /// - iOS has different constraint system
     209              : /// - Use iOS-specific constraints like `requiresCharging` instead
     210              : ///
     211              : /// ## Best Practices
     212              : ///
     213              : /// ✅ **Do** use SystemConstraints for explicit intent
     214              : /// ✅ **Do** combine with other constraints (network, charging)
     215              : /// ✅ **Do** use deviceIdle for maintenance tasks
     216              : /// ✅ **Do** use allowLowStorage/allowLowBattery for non-critical tasks
     217              : ///
     218              : /// ❌ **Don't** mix old triggers with new SystemConstraints
     219              : /// ❌ **Don't** expect SystemConstraints to work on iOS
     220              : /// ❌ **Don't** use deviceIdle for user-initiated tasks
     221              : ///
     222              : /// See also:
     223              : /// - [Constraints] - Container for all constraint types
     224              : /// - [TaskTrigger] - When tasks should execute
     225              : enum SystemConstraint {
     226              :   /// Allow task to run even when storage is low (Android only).
     227              :   ///
     228              :   /// Use this for tasks that:
     229              :   /// - Don't require much storage
     230              :   /// - Can handle low-storage conditions gracefully
     231              :   /// - Are not storage-intensive
     232              :   ///
     233              :   /// **Example**: Small API sync, log cleanup.
     234              :   allowLowStorage,
     235              : 
     236              :   /// Allow task to run even when battery is low (Android only).
     237              :   ///
     238              :   /// Use this for tasks that:
     239              :   /// - Are lightweight and quick
     240              :   /// - Don't drain battery significantly
     241              :   /// - Can tolerate battery constraints
     242              :   ///
     243              :   /// **Example**: Quick sync, small uploads.
     244              :   allowLowBattery,
     245              : 
     246              :   /// Require battery level to not be low (Android only).
     247              :   ///
     248              :   /// Task will wait until battery is above low threshold (~15%).
     249              :   ///
     250              :   /// Use this for tasks that:
     251              :   /// - Are battery-intensive
     252              :   /// - Should not drain a low battery further
     253              :   /// - Can wait for charging
     254              :   ///
     255              :   /// **Example**: Large file processing, heavy computation.
     256              :   requireBatteryNotLow,
     257              : 
     258              :   /// Require device to be idle (Android only).
     259              :   ///
     260              :   /// Device is considered idle when:
     261              :   /// - Screen is off
     262              :   /// - No user interaction
     263              :   /// - Device has been idle for a period
     264              :   ///
     265              :   /// Use this for tasks that:
     266              :   /// - Are low priority
     267              :   /// - Should not impact user experience
     268              :   /// - Can run overnight or during idle periods
     269              :   ///
     270              :   /// **Example**: Database optimization, cache cleanup, maintenance.
     271              :   deviceIdle,
     272              : }
     273              : 
     274              : /// iOS background task type selection (iOS 13.0+ only).
     275              : ///
     276              : /// **New in KMP WorkManager 2.2.0+**: Control which iOS BGTask type is used
     277              : /// for background execution. Each type has different time limits and capabilities.
     278              : ///
     279              : /// **Platform Support**: iOS only. Android ignores this setting.
     280              : ///
     281              : /// ## Task Types
     282              : ///
     283              : /// **BGAppRefreshTask (appRefresh):**
     284              : /// - Time limit: ~30 seconds total
     285              : /// - Task timeout: 20 seconds
     286              : /// - Chain timeout: 50 seconds
     287              : /// - Use case: Quick sync, small updates, lightweight operations
     288              : /// - Frequency: System-determined (multiple times per day)
     289              : ///
     290              : /// **BGProcessingTask (processing):**
     291              : /// - Time limit: 5-10 minutes
     292              : /// - Task timeout: 120 seconds (2 minutes)
     293              : /// - Chain timeout: 300 seconds (5 minutes)
     294              : /// - Use case: Heavy processing, large downloads/uploads, data migration
     295              : /// - Frequency: Less frequent (overnight, device charging)
     296              : /// - Requires: `requiresCharging` or `requiresNetwork` in constraints
     297              : ///
     298              : /// ## Auto-Selection Behavior
     299              : ///
     300              : /// If `bgTaskType` is **not specified** (null), the system auto-selects based on:
     301              : /// - `isHeavyTask = true` → BGProcessingTask
     302              : /// - `isHeavyTask = false` → BGAppRefreshTask
     303              : ///
     304              : /// ## Basic Usage
     305              : ///
     306              : /// **Auto-Selection (Recommended):**
     307              : /// ```dart
     308              : /// // System chooses based on isHeavyTask
     309              : /// await NativeWorkManager.enqueue(
     310              : ///   taskId: 'sync',
     311              : ///   trigger: TaskTrigger.oneTime(),
     312              : ///   worker: NativeWorker.httpSync(url: 'https://api.example.com/sync'),
     313              : ///   constraints: Constraints(
     314              : ///     isHeavyTask: false,  // → BGAppRefreshTask
     315              : ///   ),
     316              : /// );
     317              : /// ```
     318              : ///
     319              : /// **Manual Selection:**
     320              : /// ```dart
     321              : /// // Force BGAppRefreshTask for quick sync
     322              : /// await NativeWorkManager.enqueue(
     323              : ///   taskId: 'quick-sync',
     324              : ///   trigger: TaskTrigger.oneTime(),
     325              : ///   worker: NativeWorker.httpSync(url: 'https://api.example.com/sync'),
     326              : ///   constraints: Constraints(
     327              : ///     bgTaskType: BGTaskType.appRefresh,  // Explicit
     328              : ///     requiresNetwork: true,
     329              : ///   ),
     330              : /// );
     331              : /// ```
     332              : ///
     333              : /// ## When to Use Each Type
     334              : ///
     335              : /// **Use appRefresh for:**
     336              : /// - Quick API sync (<30s)
     337              : /// - Small data uploads
     338              : /// - Fast health checks
     339              : /// - Lightweight maintenance
     340              : /// - Frequent operations
     341              : ///
     342              : /// ```dart
     343              : /// Constraints(
     344              : ///   bgTaskType: BGTaskType.appRefresh,
     345              : ///   requiresNetwork: true,
     346              : /// )
     347              : /// ```
     348              : ///
     349              : /// **Use processing for:**
     350              : /// - Large file uploads/downloads (minutes)
     351              : /// - Video/image processing
     352              : /// - Database migrations
     353              : /// - ML model inference
     354              : /// - Batch operations
     355              : ///
     356              : /// ```dart
     357              : /// Constraints(
     358              : ///   bgTaskType: BGTaskType.processing,
     359              : ///   requiresNetwork: true,
     360              : ///   requiresCharging: true,  // Recommended
     361              : ///   isHeavyTask: true,
     362              : /// )
     363              : /// ```
     364              : ///
     365              : /// ## Time-Slicing (KMP 2.2.1+)
     366              : ///
     367              : /// For large queues, KMP WorkManager automatically:
     368              : /// - Uses 85% of available time for tasks
     369              : /// - Reserves 15% for cleanup
     370              : /// - Stops early when time is insufficient
     371              : /// - Schedules continuation for remaining tasks
     372              : ///
     373              : /// ## Info.plist Configuration
     374              : ///
     375              : /// Both task types must be declared in Info.plist:
     376              : ///
     377              : /// ```xml
     378              : /// <key>BGTaskSchedulerPermittedIdentifiers</key>
     379              : /// <array>
     380              : ///   <string>dev.brewkits.kmpworkmanager.refresh</string>
     381              : ///   <string>dev.brewkits.kmpworkmanager.processing</string>
     382              : /// </array>
     383              : /// ```
     384              : ///
     385              : /// ## Platform Behavior
     386              : ///
     387              : /// **iOS:**
     388              : /// - Maps to BGTaskScheduler API
     389              : /// - Time limits strictly enforced by iOS
     390              : /// - Processing tasks run less frequently
     391              : /// - System decides actual execution timing
     392              : ///
     393              : /// **Android:**
     394              : /// - Setting is ignored (not applicable)
     395              : /// - Android WorkManager uses different scheduling
     396              : /// - Use `isHeavyTask` for foreground service on Android
     397              : ///
     398              : /// ## Common Pitfalls
     399              : ///
     400              : /// ❌ **Don't** use processing for quick operations (wastes battery)
     401              : /// ❌ **Don't** use appRefresh for operations >30 seconds (will fail)
     402              : /// ❌ **Don't** forget Info.plist configuration (tasks won't run)
     403              : /// ❌ **Don't** rely on exact timing (iOS schedules opportunistically)
     404              : ///
     405              : /// ✅ **Do** prefer auto-selection (leave null, set isHeavyTask)
     406              : /// ✅ **Do** handle task interruption gracefully
     407              : /// ✅ **Do** use processing for long operations
     408              : /// ✅ **Do** test with actual background conditions
     409              : ///
     410              : /// ## Best Practices
     411              : ///
     412              : /// 1. **Default to auto-selection**: Let `isHeavyTask` control type
     413              : /// 2. **Test timeouts**: Verify operations complete within limits
     414              : /// 3. **Handle interruption**: Save progress if task is stopped early
     415              : /// 4. **Monitor metrics**: Use TaskEventBus for execution time tracking
     416              : /// 5. **Optimize for appRefresh**: Most tasks should complete in 30s
     417              : ///
     418              : /// ## See Also
     419              : ///
     420              : /// - [Constraints.isHeavyTask] - Auto-selects BGProcessingTask
     421              : /// - [TaskTrigger] - When tasks execute
     422              : /// - KMP WorkManager: BGTaskType enum
     423              : enum BGTaskType {
     424              :   /// BGAppRefreshTask - Quick operations (~30 seconds).
     425              :   ///
     426              :   /// **Limits**:
     427              :   /// - Total time: ~30 seconds
     428              :   /// - Task timeout: 20 seconds
     429              :   /// - Chain timeout: 50 seconds
     430              :   ///
     431              :   /// **Use Cases**: Quick sync, small uploads, health checks.
     432              :   ///
     433              :   /// **Frequency**: Multiple times per day (system-determined).
     434              :   appRefresh,
     435              : 
     436              :   /// BGProcessingTask - Heavy operations (5-10 minutes).
     437              :   ///
     438              :   /// **Limits**:
     439              :   /// - Total time: 5-10 minutes
     440              :   /// - Task timeout: 120 seconds
     441              :   /// - Chain timeout: 300 seconds
     442              :   ///
     443              :   /// **Use Cases**: Large downloads, video processing, migrations.
     444              :   ///
     445              :   /// **Frequency**: Less frequent (overnight, charging).
     446              :   ///
     447              :   /// **Requirements**: Needs `requiresCharging` or `requiresNetwork`.
     448              :   processing,
     449              : }
     450              : 
     451              : /// Android 14+ foreground service type for heavy tasks.
     452              : ///
     453              : /// **Available in native_workmanager 1.0.0+** (introduced in 0.8.0): Android 14 (API 34+)
     454              : /// requires explicit foreground service types for apps targeting SDK 34+.
     455              : ///
     456              : /// **Platform Support**: Android 14+ only. iOS and Android <14 ignore this setting.
     457              : ///
     458              : /// **Applies To**: Only relevant when `isHeavyTask = true`. Heavy tasks run as
     459              : /// foreground services with a persistent notification.
     460              : ///
     461              : /// ## Service Types
     462              : ///
     463              : /// Each type requires corresponding permissions in AndroidManifest.xml.
     464              : ///
     465              : /// **dataSync (default):**
     466              : /// - Use case: Background data upload/download, API sync, database operations
     467              : /// - Permissions: None (safe default)
     468              : /// - Validation: Always passes on Chinese ROMs (FAIL OPEN strategy)
     469              : ///
     470              : /// **location:**
     471              : /// - Use case: GPS tracking, location-based services
     472              : /// - Permissions: `ACCESS_FINE_LOCATION` or `ACCESS_COARSE_LOCATION`
     473              : /// - Manifest: `<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>`
     474              : ///
     475              : /// **mediaPlayback:**
     476              : /// - Use case: Audio/video playback, media processing
     477              : /// - Permissions: None
     478              : /// - Manifest: `<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>`
     479              : ///
     480              : /// **camera:**
     481              : /// - Use case: Camera operations, photo/video capture
     482              : /// - Permissions: `CAMERA`
     483              : /// - Manifest: `<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>`
     484              : ///
     485              : /// **microphone:**
     486              : /// - Use case: Audio recording, voice processing
     487              : /// - Permissions: `RECORD_AUDIO`
     488              : /// - Manifest: `<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"/>`
     489              : ///
     490              : /// **health:**
     491              : /// - Use case: Health/fitness data collection
     492              : /// - Permissions: `BODY_SENSORS`, `HIGH_SAMPLING_RATE_SENSORS` (if applicable)
     493              : /// - Manifest: `<uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH"/>`
     494              : ///
     495              : /// ## Basic Usage
     496              : ///
     497              : /// **Default (dataSync):**
     498              : /// ```dart
     499              : /// await NativeWorkManager.enqueue(
     500              : ///   taskId: 'large-upload',
     501              : ///   trigger: TaskTrigger.oneTime(),
     502              : ///   worker: NativeWorker.httpUpload(
     503              : ///     url: 'https://cdn.example.com/upload',
     504              : ///     filePath: '/path/to/file.zip',
     505              : ///   ),
     506              : ///   constraints: Constraints(
     507              : ///     isHeavyTask: true,  // Uses dataSync by default
     508              : ///     requiresNetwork: true,
     509              : ///   ),
     510              : /// );
     511              : /// ```
     512              : ///
     513              : /// **Location Tracking:**
     514              : /// ```dart
     515              : /// await NativeWorkManager.enqueue(
     516              : ///   taskId: 'gps-tracker',
     517              : ///   trigger: TaskTrigger.periodic(Duration(minutes: 15)),
     518              : ///   worker: DartWorker(callbackId: 'trackLocation'),
     519              : ///   constraints: Constraints(
     520              : ///     isHeavyTask: true,
     521              : ///     foregroundServiceType: ForegroundServiceType.location,
     522              : ///     requiresNetwork: true,
     523              : ///   ),
     524              : /// );
     525              : /// ```
     526              : ///
     527              : /// **Media Processing:**
     528              : /// ```dart
     529              : /// await NativeWorkManager.enqueue(
     530              : ///   taskId: 'video-encode',
     531              : ///   trigger: TaskTrigger.oneTime(),
     532              : ///   worker: DartWorker(callbackId: 'encodeVideo'),
     533              : ///   constraints: Constraints(
     534              : ///     isHeavyTask: true,
     535              : ///     foregroundServiceType: ForegroundServiceType.mediaPlayback,
     536              : ///     requiresCharging: true,
     537              : ///   ),
     538              : /// );
     539              : /// ```
     540              : ///
     541              : /// ## AndroidManifest.xml Configuration
     542              : ///
     543              : /// Add permission for the service type you're using:
     544              : ///
     545              : /// ```xml
     546              : /// <manifest>
     547              : ///   <!-- For location tasks -->
     548              : ///   <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
     549              : ///   <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     550              : ///
     551              : ///   <!-- For media tasks -->
     552              : ///   <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
     553              : ///
     554              : ///   <!-- For camera tasks -->
     555              : ///   <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>
     556              : ///   <uses-permission android:name="android.permission.CAMERA"/>
     557              : ///
     558              : ///   <!-- For microphone tasks -->
     559              : ///   <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"/>
     560              : ///   <uses-permission android:name="android.permission.RECORD_AUDIO"/>
     561              : ///
     562              : ///   <!-- For health tasks -->
     563              : ///   <uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH"/>
     564              : ///   <uses-permission android:name="android.permission.BODY_SENSORS"/>
     565              : /// </manifest>
     566              : /// ```
     567              : ///
     568              : /// ## Validation Strategy (KMP 2.1.2+)
     569              : ///
     570              : /// KMP WorkManager uses **FAIL OPEN** validation:
     571              : /// - Validates permissions on Android 14+ (API 34+)
     572              : /// - Falls back to `dataSync` if validation fails
     573              : /// - Ensures compatibility with Chinese ROMs (Xiaomi, Oppo, etc.)
     574              : /// - Never crashes due to missing permissions
     575              : ///
     576              : /// ## Platform Behavior
     577              : ///
     578              : /// **Android 14+ (API 34+):**
     579              : /// - Foreground service type is required and validated
     580              : /// - Missing permissions → fallback to dataSync
     581              : /// - Notification shows during task execution
     582              : ///
     583              : /// **Android <14:**
     584              : /// - Setting is ignored (not required)
     585              : /// - Heavy tasks still run as foreground services
     586              : /// - Any type works without validation
     587              : ///
     588              : /// **iOS:**
     589              : /// - Setting is completely ignored
     590              : /// - iOS uses BGTaskScheduler (no foreground services)
     591              : /// - Use `bgTaskType` for iOS task type selection
     592              : ///
     593              : /// ## When to Use Each Type
     594              : ///
     595              : /// | Type | Use Case | Permissions Required |
     596              : /// |------|----------|----------------------|
     597              : /// | dataSync | Default, file upload/download | None |
     598              : /// | location | GPS tracking, location services | FINE or COARSE location |
     599              : /// | mediaPlayback | Audio/video playback | None |
     600              : /// | camera | Camera operations | CAMERA |
     601              : /// | microphone | Audio recording | RECORD_AUDIO |
     602              : /// | health | Health/fitness data | BODY_SENSORS |
     603              : ///
     604              : /// ## Common Pitfalls
     605              : ///
     606              : /// ❌ **Don't** forget manifest permissions (task will fall back to dataSync)
     607              : /// ❌ **Don't** use without `isHeavyTask = true` (no effect)
     608              : /// ❌ **Don't** expect exact type on Chinese ROMs (FAIL OPEN)
     609              : /// ❌ **Don't** use for tasks <30 seconds (foreground overhead)
     610              : ///
     611              : /// ✅ **Do** add manifest permissions for your service type
     612              : /// ✅ **Do** use dataSync as safe default for uploads/downloads
     613              : /// ✅ **Do** combine with appropriate constraints
     614              : /// ✅ **Do** test on Android 14+ devices
     615              : ///
     616              : /// ## Best Practices
     617              : ///
     618              : /// 1. **Default to dataSync**: Safe for most heavy tasks
     619              : /// 2. **Add manifest entries**: Always declare required permissions
     620              : /// 3. **Test on Android 14+**: Verify behavior on modern devices
     621              : /// 4. **Handle fallback**: App works even with wrong type (falls back to dataSync)
     622              : /// 5. **Use specific types**: Only when actually accessing camera/location/etc.
     623              : ///
     624              : /// ## See Also
     625              : ///
     626              : /// - [Constraints.isHeavyTask] - Enables foreground service
     627              : /// - [BGTaskType] - iOS equivalent for task type selection
     628              : /// - KMP WorkManager: ForegroundServiceType and validation
     629              : enum ForegroundServiceType {
     630              :   /// Data synchronization (DEFAULT - Safe for all heavy tasks).
     631              :   ///
     632              :   /// **Use Case**: File uploads/downloads, API sync, database operations.
     633              :   ///
     634              :   /// **Permissions**: None required.
     635              :   ///
     636              :   /// **Validation**: Always passes (FAIL OPEN strategy).
     637              :   ///
     638              :   /// **Best for**: Most heavy tasks (default choice).
     639              :   dataSync,
     640              : 
     641              :   /// Location tracking and GPS services.
     642              :   ///
     643              :   /// **Use Case**: GPS tracking, location-based services, geofencing.
     644              :   ///
     645              :   /// **Permissions Required**:
     646              :   /// - `ACCESS_FINE_LOCATION` or `ACCESS_COARSE_LOCATION`
     647              :   /// - `FOREGROUND_SERVICE_LOCATION` (Android 14+)
     648              :   ///
     649              :   /// **Manifest**:
     650              :   /// ```xml
     651              :   /// <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
     652              :   /// ```
     653              :   location,
     654              : 
     655              :   /// Audio/video playback and media processing.
     656              :   ///
     657              :   /// **Use Case**: Audio playback, video encoding, media streaming.
     658              :   ///
     659              :   /// **Permissions Required**:
     660              :   /// - `FOREGROUND_SERVICE_MEDIA_PLAYBACK` (Android 14+)
     661              :   ///
     662              :   /// **Manifest**:
     663              :   /// ```xml
     664              :   /// <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK"/>
     665              :   /// ```
     666              :   mediaPlayback,
     667              : 
     668              :   /// Camera operations and photo/video capture.
     669              :   ///
     670              :   /// **Use Case**: Camera capture, photo processing, AR applications.
     671              :   ///
     672              :   /// **Permissions Required**:
     673              :   /// - `CAMERA`
     674              :   /// - `FOREGROUND_SERVICE_CAMERA` (Android 14+)
     675              :   ///
     676              :   /// **Manifest**:
     677              :   /// ```xml
     678              :   /// <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA"/>
     679              :   /// <uses-permission android:name="android.permission.CAMERA"/>
     680              :   /// ```
     681              :   camera,
     682              : 
     683              :   /// Microphone and audio recording.
     684              :   ///
     685              :   /// **Use Case**: Audio recording, voice recognition, speech processing.
     686              :   ///
     687              :   /// **Permissions Required**:
     688              :   /// - `RECORD_AUDIO`
     689              :   /// - `FOREGROUND_SERVICE_MICROPHONE` (Android 14+)
     690              :   ///
     691              :   /// **Manifest**:
     692              :   /// ```xml
     693              :   /// <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"/>
     694              :   /// <uses-permission android:name="android.permission.RECORD_AUDIO"/>
     695              :   /// ```
     696              :   microphone,
     697              : 
     698              :   /// Health and fitness data collection.
     699              :   ///
     700              :   /// **Use Case**: Health tracking, fitness monitoring, sensor data.
     701              :   ///
     702              :   /// **Permissions Required**:
     703              :   /// - `BODY_SENSORS`
     704              :   /// - `HIGH_SAMPLING_RATE_SENSORS` (if applicable)
     705              :   /// - `FOREGROUND_SERVICE_HEALTH` (Android 14+)
     706              :   ///
     707              :   /// **Manifest**:
     708              :   /// ```xml
     709              :   /// <uses-permission android:name="android.permission.FOREGROUND_SERVICE_HEALTH"/>
     710              :   /// <uses-permission android:name="android.permission.BODY_SENSORS"/>
     711              :   /// ```
     712              :   health,
     713              : }
     714              : 
     715              : /// Constraints that must be met before a task can run.
     716              : ///
     717              : /// Constraints optimize battery life and ensure tasks run under appropriate
     718              : /// conditions. The OS will defer task execution until all constraints are met.
     719              : ///
     720              : /// ## Basic Examples
     721              : ///
     722              : /// **Network Required:**
     723              : /// ```dart
     724              : /// await NativeWorkManager.enqueue(
     725              : ///   taskId: 'api-sync',
     726              : ///   trigger: TaskTrigger.periodic(Duration(hours: 1)),
     727              : ///   worker: NativeWorker.httpSync(url: 'https://api.example.com/sync'),
     728              : ///   constraints: Constraints.networkRequired,
     729              : /// );
     730              : /// ```
     731              : ///
     732              : /// **WiFi + Charging (Heavy Task):**
     733              : /// ```dart
     734              : /// await NativeWorkManager.enqueue(
     735              : ///   taskId: 'video-upload',
     736              : ///   trigger: TaskTrigger.oneTime(),
     737              : ///   worker: NativeWorker.httpUpload(
     738              : ///     url: 'https://cdn.example.com/videos',
     739              : ///     filePath: '/path/to/video.mp4',
     740              : ///   ),
     741              : ///   constraints: Constraints.heavyTask,
     742              : /// );
     743              : /// ```
     744              : ///
     745              : /// **Custom Constraints:**
     746              : /// ```dart
     747              : /// await NativeWorkManager.enqueue(
     748              : ///   taskId: 'db-cleanup',
     749              : ///   trigger: TaskTrigger.periodic(Duration(days: 1)),
     750              : ///   worker: DartWorker(callbackId: 'cleanupDatabase'),
     751              : ///   constraints: Constraints(
     752              : ///     requiresDeviceIdle: true,
     753              : ///     requiresBatteryNotLow: true,
     754              : ///     requiresStorageNotLow: true,
     755              : ///   ),
     756              : /// );
     757              : /// ```
     758              : ///
     759              : /// ## Common Constraint Patterns
     760              : ///
     761              : /// **Data Sync (Network Required):**
     762              : /// ```dart
     763              : /// Constraints(requiresNetwork: true)
     764              : /// ```
     765              : ///
     766              : /// **Large Upload (WiFi + Battery Safe):**
     767              : /// ```dart
     768              : /// Constraints(
     769              : ///   requiresUnmeteredNetwork: true,
     770              : ///   requiresCharging: true,
     771              : ///   isHeavyTask: true,
     772              : /// )
     773              : /// ```
     774              : ///
     775              : /// **Maintenance Task (Device Idle):**
     776              : /// ```dart
     777              : /// Constraints(
     778              : ///   requiresDeviceIdle: true,
     779              : ///   requiresBatteryNotLow: true,
     780              : /// )
     781              : /// ```
     782              : ///
     783              : /// **Critical Task (No Constraints):**
     784              : /// ```dart
     785              : /// Constraints.none // or Constraints()
     786              : /// ```
     787              : ///
     788              : /// ## Static Helpers
     789              : ///
     790              : /// - [networkRequired] - Simple network requirement
     791              : /// - [heavyTask] - WiFi + charging for large operations
     792              : /// - [none] - No constraints (runs ASAP)
     793              : ///
     794              : /// ## When to Use Constraints
     795              : ///
     796              : /// ✅ **Use constraints for:**
     797              : /// - Network-dependent operations (API calls, uploads)
     798              : /// - Battery-intensive tasks (video processing)
     799              : /// - Storage-intensive operations (downloads, caching)
     800              : /// - Maintenance work (cleanup, optimization)
     801              : ///
     802              : /// ❌ **Don't use constraints for:**
     803              : /// - Time-critical operations
     804              : /// - User-initiated actions (use no constraints)
     805              : /// - Tasks that must run immediately
     806              : ///
     807              : /// ## Battery Impact
     808              : ///
     809              : /// More constraints = Better battery life:
     810              : /// - Tasks deferred until optimal conditions
     811              : /// - OS can batch work together
     812              : /// - Prevents running on cellular data
     813              : /// - Avoids draining battery
     814              : ///
     815              : /// ## Platform Differences
     816              : ///
     817              : /// **Android:**
     818              : /// - All constraints enforced by WorkManager
     819              : /// - Very reliable constraint checking
     820              : /// - Can combine multiple constraints
     821              : ///
     822              : /// **iOS:**
     823              : /// - Constraints are advisory (not strictly enforced)
     824              : /// - Best effort by BGTaskScheduler
     825              : /// - Some constraints (requiresDeviceIdle) not available
     826              : ///
     827              : /// ## See Also
     828              : ///
     829              : /// - [BackoffPolicy] - Retry behavior on failure
     830              : /// - [QoS] - iOS task priority
     831              : /// - [ExactAlarmIOSBehavior] - iOS exact alarm handling
     832              : @immutable
     833              : class Constraints {
     834           10 :   const Constraints({
     835              :     this.requiresNetwork = false,
     836              :     this.requiresUnmeteredNetwork = false,
     837              :     this.requiresCharging = false,
     838              :     this.requiresDeviceIdle = false,
     839              :     this.requiresBatteryNotLow = false,
     840              :     this.requiresStorageNotLow = false,
     841              :     this.allowWhileIdle = false,
     842              :     this.isHeavyTask = false,
     843              :     this.qos = QoS.background,
     844              :     this.exactAlarmIOSBehavior = ExactAlarmIOSBehavior.showNotification,
     845              :     this.backoffPolicy = BackoffPolicy.exponential,
     846              :     this.backoffDelayMs = 30000,
     847              :     this.maxRetries = 3,
     848              :     this.systemConstraints = const {},
     849              :     this.bgTaskType,
     850              :     this.foregroundServiceType,
     851              :   });
     852              : 
     853              :   /// Task requires any network connection.
     854              :   final bool requiresNetwork;
     855              : 
     856              :   /// Task requires unmetered (WiFi) network.
     857              :   final bool requiresUnmeteredNetwork;
     858              : 
     859              :   /// Task requires device to be charging.
     860              :   final bool requiresCharging;
     861              : 
     862              :   /// Task requires device to be idle. (Android only)
     863              :   final bool requiresDeviceIdle;
     864              : 
     865              :   /// Task requires battery level to not be low. (Android only)
     866              :   final bool requiresBatteryNotLow;
     867              : 
     868              :   /// Task requires storage to not be low. (Android only)
     869              :   final bool requiresStorageNotLow;
     870              : 
     871              :   /// Allow task to run during Doze mode. (Android only)
     872              :   final bool allowWhileIdle;
     873              : 
     874              :   /// Indicates this is a long-running or heavy task requiring special handling.
     875              :   ///
     876              :   /// **Android**: Uses ForegroundService with persistent notification.
     877              :   /// - Task can run indefinitely while service is foreground
     878              :   /// - Prevents system from killing the task
     879              :   /// - Shows persistent notification to user
     880              :   ///
     881              :   /// **iOS**: Uses BGProcessingTask (≤60s) instead of BGAppRefreshTask (≤30s).
     882              :   /// - Double the execution time limit
     883              :   /// - Better for CPU-intensive work
     884              :   ///
     885              :   /// **Use Cases**: File upload, video processing, data migration.
     886              :   final bool isHeavyTask;
     887              : 
     888              :   /// Quality of Service hint for task priority (iOS only).
     889              :   ///
     890              :   /// **iOS**: Maps to DispatchQoS for task execution priority.
     891              :   /// **Android**: Ignored (WorkManager handles priority automatically).
     892              :   ///
     893              :   /// Default: [QoS.background]
     894              :   final QoS qos;
     895              : 
     896              :   /// iOS-specific behavior for exact time alarms.
     897              :   ///
     898              :   /// Determines how [TaskTrigger.exact()] is handled on iOS,
     899              :   /// since iOS does not support background code execution at exact times.
     900              :   ///
     901              :   /// **Android**: This field is ignored (Android always executes worker code).
     902              :   ///
     903              :   /// Default: [ExactAlarmIOSBehavior.showNotification]
     904              :   final ExactAlarmIOSBehavior exactAlarmIOSBehavior;
     905              : 
     906              :   /// Backoff policy when task fails and needs retry (Android only).
     907              :   ///
     908              :   /// **Android**: Determines retry behavior for failed WorkManager tasks.
     909              :   /// - [BackoffPolicy.exponential]: Delay doubles after each retry (30s, 60s, 120s, ...)
     910              :   /// - [BackoffPolicy.linear]: Constant delay between retries
     911              :   ///
     912              :   /// **iOS**: Not applicable (manual retry required).
     913              :   ///
     914              :   /// Default: [BackoffPolicy.exponential]
     915              :   final BackoffPolicy backoffPolicy;
     916              : 
     917              :   /// Initial backoff delay in milliseconds when task fails (Android only).
     918              :   ///
     919              :   /// **Android**: Starting delay before first retry.
     920              :   /// - Minimum: 10,000ms (10 seconds)
     921              :   /// - Subsequent retries follow [backoffPolicy]
     922              :   ///
     923              :   /// **iOS**: Not applicable.
     924              :   ///
     925              :   /// **Example**:
     926              :   /// ```dart
     927              :   /// Constraints(
     928              :   ///   backoffPolicy: BackoffPolicy.exponential,
     929              :   ///   backoffDelayMs: 30000,  // Start with 30s, then 60s, 120s, ...
     930              :   /// )
     931              :   /// ```
     932              :   ///
     933              :   /// Default: 30,000ms (30 seconds)
     934              :   final int backoffDelayMs;
     935              : 
     936              :   /// Maximum number of retry attempts when a task fails.
     937              :   ///
     938              :   /// **Android**: Maps to WorkManager's `setInputMerger` / run-attempt cap.
     939              :   /// Retries follow [backoffPolicy] and [backoffDelayMs].
     940              :   ///
     941              :   /// **iOS**: Implemented natively in the plugin's execution layer.
     942              :   /// Each retry respects [backoffPolicy] and [backoffDelayMs].
     943              :   ///
     944              :   /// - `0` — no retry (fail immediately on first failure)
     945              :   /// - `1` — try once, retry once = up to 2 total attempts
     946              :   /// - `3` — try once, retry up to 3 times = up to 4 total attempts (default)
     947              :   ///
     948              :   /// Default: 3
     949              :   final int maxRetries;
     950              : 
     951              :   /// System-level constraints for task execution (Android only).
     952              :   ///
     953              :   /// **New in KMP WorkManager 2.2.0+**: Provides cleaner way to specify
     954              :   /// system-level requirements than individual boolean flags.
     955              :   ///
     956              :   /// **Platform Support**: Android only. iOS ignores these constraints.
     957              :   ///
     958              :   /// **Available Constraints**:
     959              :   /// - [SystemConstraint.allowLowStorage] - Run even when storage is low
     960              :   /// - [SystemConstraint.allowLowBattery] - Run even when battery is low
     961              :   /// - [SystemConstraint.requireBatteryNotLow] - Wait for battery to recover
     962              :   /// - [SystemConstraint.deviceIdle] - Run only when device is idle
     963              :   ///
     964              :   /// **Example**:
     965              :   /// ```dart
     966              :   /// Constraints(
     967              :   ///   systemConstraints: {
     968              :   ///     SystemConstraint.deviceIdle,
     969              :   ///     SystemConstraint.allowLowStorage,
     970              :   ///   },
     971              :   /// )
     972              :   /// ```
     973              :   ///
     974              :   /// **Migration**: Prefer this over deprecated boolean flags
     975              :   /// (`requiresDeviceIdle`, `requiresBatteryNotLow`, `requiresStorageNotLow`).
     976              :   ///
     977              :   /// Default: Empty set (no system constraints)
     978              :   final Set<SystemConstraint> systemConstraints;
     979              : 
     980              :   /// iOS background task type selection (iOS 13.0+ only).
     981              :   ///
     982              :   /// **New in KMP WorkManager 2.2.0+**: Controls which iOS BGTask type is used
     983              :   /// for background execution (BGAppRefreshTask vs BGProcessingTask).
     984              :   ///
     985              :   /// **Platform Support**: iOS only. Android ignores this setting.
     986              :   ///
     987              :   /// **Auto-Selection**: If null (default), type is selected based on [isHeavyTask]:
     988              :   /// - `isHeavyTask = true` → BGProcessingTask (5-10 min limit)
     989              :   /// - `isHeavyTask = false` → BGAppRefreshTask (~30s limit)
     990              :   ///
     991              :   /// **Time Limits**:
     992              :   /// - appRefresh: ~30 seconds total (20s task, 50s chain)
     993              :   /// - processing: 5-10 minutes total (120s task, 300s chain)
     994              :   ///
     995              :   /// **Example** (auto-selection):
     996              :   /// ```dart
     997              :   /// Constraints(
     998              :   ///   isHeavyTask: true,  // Selects BGProcessingTask
     999              :   ///   requiresNetwork: true,
    1000              :   /// )
    1001              :   /// ```
    1002              :   ///
    1003              :   /// **Example** (manual selection):
    1004              :   /// ```dart
    1005              :   /// Constraints(
    1006              :   ///   bgTaskType: BGTaskType.appRefresh,  // Force quick task
    1007              :   ///   requiresNetwork: true,
    1008              :   /// )
    1009              :   /// ```
    1010              :   ///
    1011              :   /// **Best Practice**: Prefer auto-selection (leave null) unless you have
    1012              :   /// specific timing requirements.
    1013              :   ///
    1014              :   /// Default: null (auto-select based on isHeavyTask)
    1015              :   final BGTaskType? bgTaskType;
    1016              : 
    1017              :   /// Android 14+ foreground service type for heavy tasks.
    1018              :   ///
    1019              :   /// **New in KMP WorkManager 2.1.2+**: Controls the foreground service type
    1020              :   /// for heavy tasks on Android 14 (API 34+).
    1021              :   ///
    1022              :   /// **Platform Support**: Android 14+ only. iOS and Android <14 ignore this.
    1023              :   ///
    1024              :   /// **Applies To**: Only effective when [isHeavyTask] is `true`. Heavy tasks
    1025              :   /// run as foreground services with persistent notifications.
    1026              :   ///
    1027              :   /// **Available Types**:
    1028              :   /// - [ForegroundServiceType.dataSync] (default) - File sync, uploads, downloads
    1029              :   /// - [ForegroundServiceType.location] - GPS tracking, location services
    1030              :   /// - [ForegroundServiceType.mediaPlayback] - Audio/video playback
    1031              :   /// - [ForegroundServiceType.camera] - Camera operations
    1032              :   /// - [ForegroundServiceType.microphone] - Audio recording
    1033              :   /// - [ForegroundServiceType.health] - Health/fitness data
    1034              :   ///
    1035              :   /// **Permissions**: Each type requires manifest permissions (see [ForegroundServiceType]).
    1036              :   ///
    1037              :   /// **Validation**: KMP WorkManager uses FAIL OPEN strategy - falls back to
    1038              :   /// dataSync if validation fails. Ensures compatibility with Chinese ROMs.
    1039              :   ///
    1040              :   /// **Example** (location tracking):
    1041              :   /// ```dart
    1042              :   /// Constraints(
    1043              :   ///   isHeavyTask: true,
    1044              :   ///   foregroundServiceType: ForegroundServiceType.location,
    1045              :   ///   requiresNetwork: true,
    1046              :   /// )
    1047              :   /// ```
    1048              :   ///
    1049              :   /// **Example** (default data sync):
    1050              :   /// ```dart
    1051              :   /// Constraints(
    1052              :   ///   isHeavyTask: true,  // Uses dataSync by default
    1053              :   ///   requiresNetwork: true,
    1054              :   /// )
    1055              :   /// ```
    1056              :   ///
    1057              :   /// **Manifest Required**:
    1058              :   /// ```xml
    1059              :   /// <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION"/>
    1060              :   /// ```
    1061              :   ///
    1062              :   /// Default: null (uses dataSync)
    1063              :   final ForegroundServiceType? foregroundServiceType;
    1064              : 
    1065              :   /// Preset for network-dependent tasks.
    1066              :   ///
    1067              :   /// Use this for any task that requires network connectivity (API calls,
    1068              :   /// uploads, downloads, sync operations).
    1069              :   ///
    1070              :   /// **Equivalent to:** `Constraints(requiresNetwork: true)`
    1071              :   ///
    1072              :   /// ```dart
    1073              :   /// await NativeWorkManager.enqueue(
    1074              :   ///   taskId: 'api-sync',
    1075              :   ///   trigger: TaskTrigger.periodic(Duration(hours: 1)),
    1076              :   ///   worker: NativeWorker.httpSync(url: 'https://api.example.com/sync'),
    1077              :   ///   constraints: Constraints.networkRequired,
    1078              :   /// );
    1079              :   /// ```
    1080              :   static const Constraints networkRequired = Constraints(requiresNetwork: true);
    1081              : 
    1082              :   /// Preset for heavy tasks (should run on WiFi + Charging).
    1083              :   ///
    1084              :   /// Use this for battery-intensive or data-heavy operations like video uploads,
    1085              :   /// large file downloads, or extensive data processing. Ensures task only runs
    1086              :   /// when device is charging and on WiFi (not cellular).
    1087              :   ///
    1088              :   /// **Equivalent to:**
    1089              :   /// ```dart
    1090              :   /// Constraints(
    1091              :   ///   requiresUnmeteredNetwork: true,
    1092              :   ///   requiresCharging: true,
    1093              :   /// )
    1094              :   /// ```
    1095              :   ///
    1096              :   /// **Use cases:**
    1097              :   /// - Video upload/download
    1098              :   /// - Batch photo backup
    1099              :   /// - Large database sync
    1100              :   /// - App data backup
    1101              :   ///
    1102              :   /// ```dart
    1103              :   /// await NativeWorkManager.enqueue(
    1104              :   ///   taskId: 'video-backup',
    1105              :   ///   trigger: TaskTrigger.oneTime(),
    1106              :   ///   worker: NativeWorker.httpUpload(
    1107              :   ///     url: 'https://cdn.example.com/videos',
    1108              :   ///     filePath: '/path/to/large-video.mp4',
    1109              :   ///   ),
    1110              :   ///   constraints: Constraints.heavyTask,
    1111              :   /// );
    1112              :   /// ```
    1113              :   static const Constraints heavyTask = Constraints(
    1114              :     requiresUnmeteredNetwork: true,
    1115              :     requiresCharging: true,
    1116              :   );
    1117              : 
    1118              :   /// No constraints - task can run anytime.
    1119              :   ///
    1120              :   /// Use this for tasks that should run as soon as possible regardless of
    1121              :   /// network, battery, or charging state. Be cautious as this can impact
    1122              :   /// battery life and use cellular data.
    1123              :   ///
    1124              :   /// **Equivalent to:** `Constraints()`
    1125              :   ///
    1126              :   /// **When to use:**
    1127              :   /// - Critical user-initiated actions
    1128              :   /// - Time-sensitive operations
    1129              :   /// - Emergency tasks
    1130              :   /// - Local-only operations (no network needed)
    1131              :   ///
    1132              :   /// **When NOT to use:**
    1133              :   /// - Network-dependent tasks → Use `networkRequired`
    1134              :   /// - Large uploads/downloads → Use `heavyTask`
    1135              :   /// - Background maintenance → Use custom constraints
    1136              :   ///
    1137              :   /// ```dart
    1138              :   /// // Critical local operation - run immediately
    1139              :   /// await NativeWorkManager.enqueue(
    1140              :   ///   taskId: 'emergency-save',
    1141              :   ///   trigger: TaskTrigger.oneTime(),
    1142              :   ///   worker: DartWorker(callbackId: 'saveToLocalDb'),
    1143              :   ///   constraints: Constraints.none,
    1144              :   /// );
    1145              :   /// ```
    1146              :   static const Constraints none = Constraints();
    1147              : 
    1148              :   /// Convert to map for platform channel.
    1149           12 :   Map<String, dynamic> toMap() => {
    1150            6 :         'requiresNetwork': requiresNetwork,
    1151            6 :         'requiresUnmeteredNetwork': requiresUnmeteredNetwork,
    1152            6 :         'requiresCharging': requiresCharging,
    1153            6 :         'requiresDeviceIdle': requiresDeviceIdle,
    1154            6 :         'requiresBatteryNotLow': requiresBatteryNotLow,
    1155            6 :         'requiresStorageNotLow': requiresStorageNotLow,
    1156            6 :         'allowWhileIdle': allowWhileIdle,
    1157            6 :         'isHeavyTask': isHeavyTask,
    1158           12 :         'qos': qos.name,
    1159           12 :         'exactAlarmIOSBehavior': exactAlarmIOSBehavior.name,
    1160           12 :         'backoffPolicy': backoffPolicy.name,
    1161            6 :         'backoffDelayMs': backoffDelayMs,
    1162            6 :         'maxRetries': maxRetries,
    1163           20 :         'systemConstraints': systemConstraints.map((c) => c.name).toList(),
    1164            7 :         'bgTaskType': bgTaskType?.name,
    1165            7 :         'foregroundServiceType': foregroundServiceType?.name,
    1166              :       };
    1167              : 
    1168              :   /// Create from map.
    1169            4 :   factory Constraints.fromMap(Map<String, dynamic> map) => Constraints(
    1170            2 :         requiresNetwork: map['requiresNetwork'] as bool? ?? false,
    1171              :         requiresUnmeteredNetwork:
    1172            2 :             map['requiresUnmeteredNetwork'] as bool? ?? false,
    1173            2 :         requiresCharging: map['requiresCharging'] as bool? ?? false,
    1174            2 :         requiresDeviceIdle: map['requiresDeviceIdle'] as bool? ?? false,
    1175            2 :         requiresBatteryNotLow: map['requiresBatteryNotLow'] as bool? ?? false,
    1176            2 :         requiresStorageNotLow: map['requiresStorageNotLow'] as bool? ?? false,
    1177            2 :         allowWhileIdle: map['allowWhileIdle'] as bool? ?? false,
    1178            2 :         isHeavyTask: map['isHeavyTask'] as bool? ?? false,
    1179            2 :         qos: QoS.values.firstWhere(
    1180            8 :           (e) => e.name == map['qos'],
    1181            0 :           orElse: () => QoS.background,
    1182              :         ),
    1183            2 :         exactAlarmIOSBehavior: ExactAlarmIOSBehavior.values.firstWhere(
    1184            8 :           (e) => e.name == map['exactAlarmIOSBehavior'],
    1185            0 :           orElse: () => ExactAlarmIOSBehavior.showNotification,
    1186              :         ),
    1187            2 :         backoffPolicy: BackoffPolicy.values.firstWhere(
    1188            8 :           (e) => e.name == map['backoffPolicy'],
    1189            0 :           orElse: () => BackoffPolicy.exponential,
    1190              :         ),
    1191            2 :         backoffDelayMs: map['backoffDelayMs'] as int? ?? 30000,
    1192            2 :         maxRetries: map['maxRetries'] as int? ?? 3,
    1193            2 :         systemConstraints: (map['systemConstraints'] as List<dynamic>?)
    1194            3 :                 ?.map((name) => SystemConstraint.values
    1195            1 :                     .where(
    1196            3 :                       (e) => e.name == name,
    1197              :                     )
    1198            1 :                     .firstOrNull)
    1199            2 :                 .whereType<SystemConstraint>()
    1200            2 :                 .toSet() ??
    1201              :             {},
    1202            2 :         bgTaskType: map['bgTaskType'] != null
    1203              :             ? BGTaskType.values
    1204            1 :                 .where(
    1205            4 :                   (e) => e.name == map['bgTaskType'],
    1206              :                 )
    1207            1 :                 .firstOrNull
    1208              :             : null,
    1209            2 :         foregroundServiceType: map['foregroundServiceType'] != null
    1210              :             ? ForegroundServiceType.values
    1211            1 :                 .where(
    1212            4 :                   (e) => e.name == map['foregroundServiceType'],
    1213              :                 )
    1214            1 :                 .firstOrNull
    1215              :             : null,
    1216              :       );
    1217              : 
    1218              :   /// Create a copy with updated values.
    1219            3 :   Constraints copyWith({
    1220              :     bool? requiresNetwork,
    1221              :     bool? requiresUnmeteredNetwork,
    1222              :     bool? requiresCharging,
    1223              :     bool? requiresDeviceIdle,
    1224              :     bool? requiresBatteryNotLow,
    1225              :     bool? requiresStorageNotLow,
    1226              :     bool? allowWhileIdle,
    1227              :     bool? isHeavyTask,
    1228              :     QoS? qos,
    1229              :     ExactAlarmIOSBehavior? exactAlarmIOSBehavior,
    1230              :     BackoffPolicy? backoffPolicy,
    1231              :     int? backoffDelayMs,
    1232              :     int? maxRetries,
    1233              :     Set<SystemConstraint>? systemConstraints,
    1234              :     BGTaskType? bgTaskType,
    1235              :     ForegroundServiceType? foregroundServiceType,
    1236              :   }) =>
    1237            3 :       Constraints(
    1238            3 :         requiresNetwork: requiresNetwork ?? this.requiresNetwork,
    1239              :         requiresUnmeteredNetwork:
    1240            3 :             requiresUnmeteredNetwork ?? this.requiresUnmeteredNetwork,
    1241            3 :         requiresCharging: requiresCharging ?? this.requiresCharging,
    1242            3 :         requiresDeviceIdle: requiresDeviceIdle ?? this.requiresDeviceIdle,
    1243              :         requiresBatteryNotLow:
    1244            3 :             requiresBatteryNotLow ?? this.requiresBatteryNotLow,
    1245              :         requiresStorageNotLow:
    1246            3 :             requiresStorageNotLow ?? this.requiresStorageNotLow,
    1247            3 :         allowWhileIdle: allowWhileIdle ?? this.allowWhileIdle,
    1248            1 :         isHeavyTask: isHeavyTask ?? this.isHeavyTask,
    1249            3 :         qos: qos ?? this.qos,
    1250              :         exactAlarmIOSBehavior:
    1251            3 :             exactAlarmIOSBehavior ?? this.exactAlarmIOSBehavior,
    1252            3 :         backoffPolicy: backoffPolicy ?? this.backoffPolicy,
    1253            3 :         backoffDelayMs: backoffDelayMs ?? this.backoffDelayMs,
    1254            3 :         maxRetries: maxRetries ?? this.maxRetries,
    1255            3 :         systemConstraints: systemConstraints ?? this.systemConstraints,
    1256            3 :         bgTaskType: bgTaskType ?? this.bgTaskType,
    1257              :         foregroundServiceType:
    1258            3 :             foregroundServiceType ?? this.foregroundServiceType,
    1259              :       );
    1260              : 
    1261            2 :   @override
    1262              :   bool operator ==(Object other) =>
    1263              :       identical(this, other) ||
    1264            1 :       other is Constraints &&
    1265            3 :           requiresNetwork == other.requiresNetwork &&
    1266            3 :           requiresUnmeteredNetwork == other.requiresUnmeteredNetwork &&
    1267            3 :           requiresCharging == other.requiresCharging &&
    1268            3 :           requiresDeviceIdle == other.requiresDeviceIdle &&
    1269            3 :           requiresBatteryNotLow == other.requiresBatteryNotLow &&
    1270            3 :           requiresStorageNotLow == other.requiresStorageNotLow &&
    1271            3 :           allowWhileIdle == other.allowWhileIdle &&
    1272            3 :           isHeavyTask == other.isHeavyTask &&
    1273            3 :           qos == other.qos &&
    1274            3 :           exactAlarmIOSBehavior == other.exactAlarmIOSBehavior &&
    1275            3 :           backoffPolicy == other.backoffPolicy &&
    1276            3 :           backoffDelayMs == other.backoffDelayMs &&
    1277            3 :           maxRetries == other.maxRetries &&
    1278            3 :           setEquals(systemConstraints, other.systemConstraints) &&
    1279            3 :           bgTaskType == other.bgTaskType &&
    1280            3 :           foregroundServiceType == other.foregroundServiceType;
    1281              : 
    1282            1 :   @override
    1283            1 :   int get hashCode => Object.hash(
    1284            1 :         requiresNetwork,
    1285            1 :         requiresUnmeteredNetwork,
    1286            1 :         requiresCharging,
    1287            1 :         requiresDeviceIdle,
    1288            1 :         requiresBatteryNotLow,
    1289            1 :         requiresStorageNotLow,
    1290            1 :         allowWhileIdle,
    1291            1 :         isHeavyTask,
    1292            1 :         qos,
    1293            1 :         exactAlarmIOSBehavior,
    1294            1 :         backoffPolicy,
    1295            1 :         backoffDelayMs,
    1296            1 :         maxRetries,
    1297            2 :         Object.hashAll(systemConstraints),
    1298            1 :         bgTaskType,
    1299            1 :         foregroundServiceType,
    1300              :       );
    1301              : 
    1302            0 :   @override
    1303            0 :   String toString() => 'Constraints('
    1304            0 :       'network: $requiresNetwork, '
    1305            0 :       'unmetered: $requiresUnmeteredNetwork, '
    1306            0 :       'charging: $requiresCharging, '
    1307            0 :       'idle: $requiresDeviceIdle, '
    1308            0 :       'batteryOk: $requiresBatteryNotLow, '
    1309            0 :       'storageOk: $requiresStorageNotLow, '
    1310            0 :       'allowIdle: $allowWhileIdle, '
    1311            0 :       'heavy: $isHeavyTask, '
    1312            0 :       'qos: ${qos.name}, '
    1313            0 :       'iosAlarm: ${exactAlarmIOSBehavior.name}, '
    1314            0 :       'backoff: ${backoffPolicy.name}, '
    1315            0 :       'backoffDelay: ${backoffDelayMs}ms)';
    1316              : }
        

Generated by: LCOV version 2.4-0