refactor(android)!: restructure to standard Capacitor plugin layout
Restructure Android project from nested module layout to standard Capacitor plugin structure following community conventions. Structure Changes: - Move plugin code from android/plugin/ to android/src/main/java/ - Move test app from android/app/ to test-apps/android-test-app/app/ - Remove nested android/plugin module structure - Remove nested android/app test app structure Build Infrastructure: - Add Gradle wrapper files (gradlew, gradlew.bat, gradle/wrapper/) - Transform android/build.gradle from root project to library module - Update android/settings.gradle for standalone plugin builds - Add android/gradle.properties with AndroidX configuration - Add android/consumer-rules.pro for ProGuard rules Configuration Updates: - Add prepare script to package.json for automatic builds on npm install - Update package.json version to 1.0.1 - Update android/build.gradle to properly resolve Capacitor dependencies - Update test-apps/android-test-app/settings.gradle with correct paths - Remove android/variables.gradle (hardcode values in build.gradle) Documentation: - Update BUILDING.md with new structure and build process - Update INTEGRATION_GUIDE.md to reflect standard structure - Update README.md to remove path fix warnings - Add test-apps/BUILD_PROCESS.md documenting test app build flows Test App Configuration: - Fix android-test-app to correctly reference plugin and Capacitor - Remove capacitor-cordova-android-plugins dependency (not needed) - Update capacitor.settings.gradle path verification in fix script BREAKING CHANGE: Plugin now uses standard Capacitor Android structure. Consuming apps must update their capacitor.settings.gradle to reference android/ instead of android/plugin/. This is automatically handled by Capacitor CLI for apps using standard plugin installation.
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
/**
|
||||
* SchedulingPolicy.java
|
||||
*
|
||||
* Policy configuration for notification scheduling, fetching, and retry behavior.
|
||||
*
|
||||
* This class is part of the Integration Point Refactor (PR1) SPI implementation.
|
||||
* It allows host apps to configure scheduling behavior including retry backoff,
|
||||
* prefetch timing, deduplication windows, and cache TTL.
|
||||
*
|
||||
* @author Matthew Raymer
|
||||
* @version 1.0.0
|
||||
*/
|
||||
|
||||
package com.timesafari.dailynotification;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Scheduling policy configuration
|
||||
*
|
||||
* Controls how the plugin schedules fetches, handles retries, manages
|
||||
* deduplication, and enforces TTL policies.
|
||||
*
|
||||
* This follows the TypeScript interface from src/types/content-fetcher.ts
|
||||
* and ensures consistency between JS and native configuration.
|
||||
*/
|
||||
public class SchedulingPolicy {
|
||||
|
||||
/**
|
||||
* How early to prefetch before scheduled notification time (milliseconds)
|
||||
*
|
||||
* Example: If set to 300000 (5 minutes), and notification is scheduled for
|
||||
* 8:00 AM, the fetch will be triggered at 7:55 AM.
|
||||
*
|
||||
* Default: 5 minutes (300000ms)
|
||||
*/
|
||||
@Nullable
|
||||
public Long prefetchWindowMs;
|
||||
|
||||
/**
|
||||
* Retry backoff configuration (required)
|
||||
*
|
||||
* Controls exponential backoff behavior for failed fetches
|
||||
*/
|
||||
@NonNull
|
||||
public RetryBackoff retryBackoff;
|
||||
|
||||
/**
|
||||
* Maximum items to fetch per batch
|
||||
*
|
||||
* Limits the number of NotificationContent items that can be fetched
|
||||
* in a single operation. Helps prevent oversized responses.
|
||||
*
|
||||
* Default: 50
|
||||
*/
|
||||
@Nullable
|
||||
public Integer maxBatchSize;
|
||||
|
||||
/**
|
||||
* Deduplication window (milliseconds)
|
||||
*
|
||||
* Prevents duplicate notifications within this time window. Plugin
|
||||
* uses dedupeKey (or id) to detect duplicates.
|
||||
*
|
||||
* Default: 24 hours (86400000ms)
|
||||
*/
|
||||
@Nullable
|
||||
public Long dedupeHorizonMs;
|
||||
|
||||
/**
|
||||
* Default cache TTL if item doesn't specify ttlSeconds (seconds)
|
||||
*
|
||||
* Used when NotificationContent doesn't have ttlSeconds set.
|
||||
* Determines how long cached content remains valid.
|
||||
*
|
||||
* Default: 6 hours (21600 seconds)
|
||||
*/
|
||||
@Nullable
|
||||
public Integer cacheTtlSeconds;
|
||||
|
||||
/**
|
||||
* Whether exact alarms are allowed (Android 12+)
|
||||
*
|
||||
* Controls whether plugin should attempt to use exact alarms.
|
||||
* Requires SCHEDULE_EXACT_ALARM permission on Android 12+.
|
||||
*
|
||||
* Default: false (use inexact alarms)
|
||||
*/
|
||||
@Nullable
|
||||
public Boolean exactAlarmsAllowed;
|
||||
|
||||
/**
|
||||
* Fetch timeout in milliseconds
|
||||
*
|
||||
* Maximum time to wait for native fetcher to complete.
|
||||
* Plugin enforces this timeout when calling fetchContent().
|
||||
*
|
||||
* Default: 30 seconds (30000ms)
|
||||
*/
|
||||
@Nullable
|
||||
public Long fetchTimeoutMs;
|
||||
|
||||
/**
|
||||
* Default constructor with required field
|
||||
*
|
||||
* @param retryBackoff Retry backoff configuration (required)
|
||||
*/
|
||||
public SchedulingPolicy(@NonNull RetryBackoff retryBackoff) {
|
||||
this.retryBackoff = retryBackoff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry backoff configuration
|
||||
*
|
||||
* Controls exponential backoff behavior for retryable failures.
|
||||
* Delay = min(max(minMs, lastDelay * factor), maxMs) * (1 + jitterPct/100 * random)
|
||||
*/
|
||||
public static class RetryBackoff {
|
||||
|
||||
/**
|
||||
* Minimum delay between retries (milliseconds)
|
||||
*
|
||||
* First retry will wait at least this long.
|
||||
* Default: 2000ms (2 seconds)
|
||||
*/
|
||||
public long minMs;
|
||||
|
||||
/**
|
||||
* Maximum delay between retries (milliseconds)
|
||||
*
|
||||
* Retry delay will never exceed this value.
|
||||
* Default: 600000ms (10 minutes)
|
||||
*/
|
||||
public long maxMs;
|
||||
|
||||
/**
|
||||
* Exponential backoff multiplier
|
||||
*
|
||||
* Each retry multiplies previous delay by this factor.
|
||||
* Example: factor=2 means delays: 2s, 4s, 8s, 16s, ...
|
||||
* Default: 2.0
|
||||
*/
|
||||
public double factor;
|
||||
|
||||
/**
|
||||
* Jitter percentage (0-100)
|
||||
*
|
||||
* Adds randomness to prevent thundering herd.
|
||||
* Final delay = calculatedDelay * (1 + jitterPct/100 * random(0-1))
|
||||
* Default: 20 (20% jitter)
|
||||
*/
|
||||
public int jitterPct;
|
||||
|
||||
/**
|
||||
* Default constructor with sensible defaults
|
||||
*/
|
||||
public RetryBackoff() {
|
||||
this.minMs = 2000;
|
||||
this.maxMs = 600000;
|
||||
this.factor = 2.0;
|
||||
this.jitterPct = 20;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with all parameters
|
||||
*
|
||||
* @param minMs Minimum delay (ms)
|
||||
* @param maxMs Maximum delay (ms)
|
||||
* @param factor Exponential multiplier
|
||||
* @param jitterPct Jitter percentage (0-100)
|
||||
*/
|
||||
public RetryBackoff(long minMs, long maxMs, double factor, int jitterPct) {
|
||||
this.minMs = minMs;
|
||||
this.maxMs = maxMs;
|
||||
this.factor = factor;
|
||||
this.jitterPct = jitterPct;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create default policy with sensible defaults
|
||||
*
|
||||
* @return Default SchedulingPolicy instance
|
||||
*/
|
||||
@NonNull
|
||||
public static SchedulingPolicy createDefault() {
|
||||
SchedulingPolicy policy = new SchedulingPolicy(new RetryBackoff());
|
||||
policy.prefetchWindowMs = 300000L; // 5 minutes
|
||||
policy.maxBatchSize = 50;
|
||||
policy.dedupeHorizonMs = 86400000L; // 24 hours
|
||||
policy.cacheTtlSeconds = 21600; // 6 hours
|
||||
policy.exactAlarmsAllowed = false;
|
||||
policy.fetchTimeoutMs = 30000L; // 30 seconds
|
||||
return policy;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user