diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..f91f646
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,12 @@
+#
+# https://help.github.com/articles/dealing-with-line-endings/
+#
+# Linux start script should use lf
+/gradlew        text eol=lf
+
+# These are Windows script files and should use crlf
+*.bat           text eol=crlf
+
+# Binary files should be left untouched
+*.jar           binary
+
diff --git a/.gitignore b/.gitignore
index 3371289..34d3813 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,9 @@ Pods/
 .vscode/
 build/
 *.tgz
+
+# Ignore Gradle project-specific cache directory
+.gradle
+
+# Ignore Gradle build output directory
+build
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 9b71034..0bb3814 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,13 +1,15 @@
 apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'jacoco'
 
 android {
     namespace "com.timesafari.dailynotification"
-    compileSdkVersion rootProject.ext.compileSdkVersion
-    buildToolsVersion rootProject.ext.buildToolsVersion
+    compileSdkVersion 33
+    buildToolsVersion "33.0.2"
     defaultConfig {
         applicationId "com.timesafari.dailynotification"
         minSdkVersion 22
-        targetSdkVersion rootProject.ext.targetSdkVersion
+        targetSdkVersion 33
         versionCode 1
         versionName "1.0"
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -20,15 +22,20 @@ android {
     buildTypes {
         release {
             minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
     }
     lintOptions {
         abortOnError false
     }
     compileOptions {
-        sourceCompatibility JavaVersion.VERSION_11
-        targetCompatibility JavaVersion.VERSION_11
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+    testOptions {
+        unitTests.all {
+            useJUnitPlatform()
+        }
     }
 }
 
@@ -44,15 +51,69 @@ repositories {
 }
 
 dependencies {
-    implementation fileTree(dir: 'libs', include: ['*.jar'])
-    implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
-    implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
-    implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
+    implementation fileTree(include: ['*.jar'], dir: 'libs')
     implementation project(':capacitor-android')
+    implementation project(':capacitor-cordova-android-plugins')
+    
+    // Android SDK
+    implementation 'com.android.support:support-v4:28.0.0'
+    implementation 'com.android.support:appcompat-v7:28.0.0'
+    implementation 'com.android.support:design:28.0.0'
+    
+    // AndroidX Core
+    implementation 'androidx.core:core:1.9.0'
+    implementation 'androidx.core:core-ktx:1.12.0'
+    
+    // AndroidX AppCompat
+    implementation 'androidx.appcompat:appcompat:1.6.1'
+    
+    // AndroidX Test
+    testImplementation 'androidx.test:core:1.5.0'
+    testImplementation 'androidx.test:runner:1.5.2'
+    testImplementation 'androidx.test.ext:junit:1.1.5'
+    testImplementation 'androidx.test.espresso:espresso-core:3.5.1'
+    testImplementation 'androidx.test:rules:1.5.0'
+    testImplementation 'androidx.test:core-ktx:1.5.0'
+    
+    // JUnit
     testImplementation 'junit:junit:4.13.2'
+    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.9.2'
+    testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.9.2'
+    
+    // Mockito
+    testImplementation 'org.mockito:mockito-core:4.5.1'
+    testImplementation 'org.mockito:mockito-inline:4.5.1'
+    
+    // AndroidX WorkManager
+    implementation 'androidx.work:work-runtime:2.8.1'
+    
+    // AndroidX Room (for local storage)
+    implementation 'androidx.room:room-runtime:2.6.1'
+    annotationProcessor 'androidx.room:room-compiler:2.6.1'
+    
+    // AndroidX Lifecycle
+    implementation 'androidx.lifecycle:lifecycle-runtime:2.7.0'
+    implementation 'androidx.lifecycle:lifecycle-common-java8:2.7.0'
+    
+    // AndroidX Security
+    implementation 'androidx.security:security-crypto:1.1.0-alpha06'
+    
+    // AndroidX Notification
+    implementation 'androidx.media:media:1.7.0'
+    
+    // AndroidX Broadcast
+    implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0'
+
+    // Capacitor dependencies
+    implementation 'com.getcapacitor:capacitor:5.0.0'
+    implementation 'com.getcapacitor:capacitor-android:5.0.0'
+
+    // Testing dependencies
     androidTestImplementation 'androidx.test.ext:junit:1.1.5'
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
-    implementation project(':capacitor-cordova-android-plugins')
+    androidTestImplementation 'androidx.test:runner:1.5.2'
+    androidTestImplementation 'androidx.test:rules:1.5.0'
+    androidTestImplementation 'org.mockito:mockito-android:4.5.1'
 }
 
 apply from: 'capacitor.build.gradle'
@@ -63,5 +124,5 @@ try {
         apply plugin: 'com.google.gms.google-services'
     }
 } catch(Exception e) {
-    logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
+    logger.warn("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
 }
diff --git a/android/app/src/androidTest/java/com/timesafari/dailynotification/.LCKDailyNotificationPluginTest.java~ b/android/app/src/androidTest/java/com/timesafari/dailynotification/.LCKDailyNotificationPluginTest.java~
new file mode 100644
index 0000000..146077b
--- /dev/null
+++ b/android/app/src/androidTest/java/com/timesafari/dailynotification/.LCKDailyNotificationPluginTest.java~
@@ -0,0 +1 @@
+/home/matthew/projects/timesafari/daily-notification-plugin/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationPluginTest.java
\ No newline at end of file
diff --git a/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationConfigTest.java b/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationConfigTest.java
new file mode 100644
index 0000000..bde1c97
--- /dev/null
+++ b/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationConfigTest.java
@@ -0,0 +1,104 @@
+/**
+ * DailyNotificationConfigTest.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Tests for the DailyNotificationConfig
+ * 
+ * Features:
+ * - Unit tests
+ * - Singleton pattern
+ * - Configuration management
+ * - Default values
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import java.util.TimeZone;
+
+import static org.junit.Assert.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DailyNotificationConfigTest {
+    private DailyNotificationConfig config;
+    
+    @Before
+    public void setUp() {
+        config = DailyNotificationConfig.getInstance();
+    }
+    
+    @Test
+    public void testSingletonPattern() {
+        DailyNotificationConfig config2 = DailyNotificationConfig.getInstance();
+        assertSame("Config instances should be the same", config, config2);
+    }
+    
+    @Test
+    public void testDefaultValues() {
+        assertEquals("Default max notifications should be 10", 10, 
+                    config.getMaxNotificationsPerDay());
+        assertEquals("Default timezone should be system default", 
+                    TimeZone.getDefault(), config.getDefaultTimeZone());
+        assertTrue("Default logging should be enabled", config.isLoggingEnabled());
+        assertEquals("Default retention days should be 7", 7, 
+                    config.getRetentionDays());
+    }
+    
+    @Test
+    public void testMaxNotificationsPerDay() {
+        config.setMaxNotificationsPerDay(5);
+        assertEquals("Max notifications should be 5", 5, 
+                    config.getMaxNotificationsPerDay());
+    }
+    
+    @Test
+    public void testDefaultTimeZone() {
+        TimeZone newTimeZone = TimeZone.getTimeZone("America/New_York");
+        config.setDefaultTimeZone(newTimeZone);
+        assertEquals("Default timezone should be America/New_York", 
+                    newTimeZone, config.getDefaultTimeZone());
+    }
+    
+    @Test
+    public void testLoggingEnabled() {
+        config.setLoggingEnabled(false);
+        assertFalse("Logging should be disabled", config.isLoggingEnabled());
+        
+        config.setLoggingEnabled(true);
+        assertTrue("Logging should be enabled", config.isLoggingEnabled());
+    }
+    
+    @Test
+    public void testRetentionDays() {
+        config.setRetentionDays(14);
+        assertEquals("Retention days should be 14", 14, 
+                    config.getRetentionDays());
+    }
+    
+    @Test
+    public void testResetToDefaults() {
+        // Change values
+        config.setMaxNotificationsPerDay(5);
+        config.setDefaultTimeZone(TimeZone.getTimeZone("America/New_York"));
+        config.setLoggingEnabled(false);
+        config.setRetentionDays(14);
+        
+        // Reset to defaults
+        config.resetToDefaults();
+        
+        // Verify defaults
+        assertEquals("Max notifications should be reset to 10", 10, 
+                    config.getMaxNotificationsPerDay());
+        assertEquals("Default timezone should be reset to system default", 
+                    TimeZone.getDefault(), config.getDefaultTimeZone());
+        assertTrue("Logging should be reset to enabled", config.isLoggingEnabled());
+        assertEquals("Retention days should be reset to 7", 7, 
+                    config.getRetentionDays());
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationConstantsTest.java b/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationConstantsTest.java
new file mode 100644
index 0000000..7d91baa
--- /dev/null
+++ b/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationConstantsTest.java
@@ -0,0 +1,126 @@
+/**
+ * DailyNotificationConstantsTest.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Tests for the DailyNotificationConstants
+ * 
+ * Features:
+ * - Unit tests
+ * - Constant validation
+ * - Default values
+ * - Error messages
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DailyNotificationConstantsTest {
+    
+    @Test
+    public void testDefaultValues() {
+        assertEquals("Default title should be 'Daily Notification'", 
+                    "Daily Notification", DailyNotificationConstants.DEFAULT_TITLE);
+        assertEquals("Default body should be 'Your daily update is ready'", 
+                    "Your daily update is ready", DailyNotificationConstants.DEFAULT_BODY);
+    }
+    
+    @Test
+    public void testNotificationIdentifiers() {
+        assertTrue("Notification ID prefix should start with 'daily-notification-'", 
+                  DailyNotificationConstants.NOTIFICATION_ID_PREFIX.startsWith("daily-notification-"));
+        assertEquals("Event name should be 'notification'", 
+                    "notification", DailyNotificationConstants.EVENT_NAME);
+    }
+    
+    @Test
+    public void testSettingsKeys() {
+        assertEquals("Sound setting key should be 'sound'", 
+                    "sound", DailyNotificationConstants.Settings.SOUND);
+        assertEquals("Priority setting key should be 'priority'", 
+                    "priority", DailyNotificationConstants.Settings.PRIORITY);
+        assertEquals("Timezone setting key should be 'timezone'", 
+                    "timezone", DailyNotificationConstants.Settings.TIMEZONE);
+        assertEquals("Retry count setting key should be 'retryCount'", 
+                    "retryCount", DailyNotificationConstants.Settings.RETRY_COUNT);
+        assertEquals("Retry interval setting key should be 'retryInterval'", 
+                    "retryInterval", DailyNotificationConstants.Settings.RETRY_INTERVAL);
+    }
+    
+    @Test
+    public void testSettingsDefaultValues() {
+        assertTrue("Default sound should be true", 
+                  DailyNotificationConstants.Settings.DEFAULT_SOUND);
+        assertEquals("Default priority should be 'default'", 
+                    "default", DailyNotificationConstants.Settings.DEFAULT_PRIORITY);
+        assertEquals("Default retry count should be 3", 
+                    3, DailyNotificationConstants.Settings.DEFAULT_RETRY_COUNT);
+        assertEquals("Default retry interval should be 1000", 
+                    1000, DailyNotificationConstants.Settings.DEFAULT_RETRY_INTERVAL);
+    }
+    
+    @Test
+    public void testPluginMethodKeys() {
+        assertEquals("URL key should be 'url'", 
+                    "url", DailyNotificationConstants.Keys.URL);
+        assertEquals("Time key should be 'time'", 
+                    "time", DailyNotificationConstants.Keys.TIME);
+        assertEquals("Title key should be 'title'", 
+                    "title", DailyNotificationConstants.Keys.TITLE);
+        assertEquals("Body key should be 'body'", 
+                    "body", DailyNotificationConstants.Keys.BODY);
+        assertEquals("Sound key should be 'sound'", 
+                    "sound", DailyNotificationConstants.Keys.SOUND);
+        assertEquals("Priority key should be 'priority'", 
+                    "priority", DailyNotificationConstants.Keys.PRIORITY);
+        assertEquals("Timezone key should be 'timezone'", 
+                    "timezone", DailyNotificationConstants.Keys.TIMEZONE);
+    }
+    
+    @Test
+    public void testChannelSettings() {
+        assertEquals("Channel ID should be 'daily_notification_channel'", 
+                    "daily_notification_channel", DailyNotificationConstants.Channel.ID);
+        assertEquals("Channel name should be 'Daily Notifications'", 
+                    "Daily Notifications", DailyNotificationConstants.Channel.NAME);
+        assertEquals("Channel description should be 'Daily notification updates'", 
+                    "Daily notification updates", DailyNotificationConstants.Channel.DESCRIPTION);
+        assertTrue("Channel should enable vibration", 
+                  DailyNotificationConstants.Channel.ENABLE_VIBRATION);
+        assertTrue("Channel should enable lights", 
+                  DailyNotificationConstants.Channel.ENABLE_LIGHTS);
+    }
+    
+    @Test
+    public void testTimeConstants() {
+        assertEquals("Milliseconds per day should be 86400000", 
+                    86400000, DailyNotificationConstants.Time.MILLIS_PER_DAY);
+        assertEquals("Maximum hours should be 24", 
+                    24, DailyNotificationConstants.Time.MAX_HOURS);
+        assertEquals("Maximum minutes should be 60", 
+                    60, DailyNotificationConstants.Time.MAX_MINUTES);
+    }
+    
+    @Test
+    public void testErrorMessages() {
+        assertEquals("Missing parameters error message should be correct", 
+                    "Missing required parameters", DailyNotificationConstants.Errors.MISSING_PARAMS);
+        assertEquals("Invalid time error message should be correct", 
+                    "Invalid time format", DailyNotificationConstants.Errors.INVALID_TIME);
+        assertEquals("Invalid timezone error message should be correct", 
+                    "Invalid timezone", DailyNotificationConstants.Errors.INVALID_TIMEZONE);
+        assertEquals("Invalid priority error message should be correct", 
+                    "Invalid priority value", DailyNotificationConstants.Errors.INVALID_PRIORITY);
+        assertEquals("Scheduling failed error message should be correct", 
+                    "Failed to schedule notification", DailyNotificationConstants.Errors.SCHEDULING_FAILED);
+        assertEquals("Permission denied error message should be correct", 
+                    "Notification permission denied", DailyNotificationConstants.Errors.PERMISSION_DENIED);
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationLoggerTest.java b/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationLoggerTest.java
new file mode 100644
index 0000000..b831caf
--- /dev/null
+++ b/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationLoggerTest.java
@@ -0,0 +1,84 @@
+/**
+ * DailyNotificationLoggerTest.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Tests for the DailyNotificationLogger
+ * 
+ * Features:
+ * - Unit tests
+ * - Log level testing
+ * - Logging configuration
+ * - Error handling
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import static org.mockito.Mockito.*;
+
+@RunWith(MockitoJUnitRunner.class)
+public class DailyNotificationLoggerTest {
+    private DailyNotificationLogger logger;
+    
+    @Before
+    public void setUp() {
+        logger = new DailyNotificationLogger();
+        MockitoAnnotations.openMocks(this);
+    }
+    
+    @Test
+    public void testLogLevels() {
+        // Test each log level
+        logger.log("Debug message", DailyNotificationLogger.Level.DEBUG);
+        logger.log("Info message", DailyNotificationLogger.Level.INFO);
+        logger.log("Warning message", DailyNotificationLogger.Level.WARNING);
+        logger.log("Error message", DailyNotificationLogger.Level.ERROR);
+        
+        // Note: Actual verification would require capturing log output
+    }
+    
+    @Test
+    public void testLogWithThrowable() {
+        Exception e = new Exception("Test exception");
+        logger.log("Error with exception", DailyNotificationLogger.Level.ERROR, e);
+        
+        // Note: Actual verification would require capturing log output
+    }
+    
+    @Test
+    public void testLoggingEnabled() {
+        // Test logging enabled
+        assertTrue(DailyNotificationLogger.isLoggingEnabled());
+        
+        // Disable logging
+        DailyNotificationLogger.setLoggingEnabled(false);
+        assertFalse(DailyNotificationLogger.isLoggingEnabled());
+        
+        // Re-enable logging
+        DailyNotificationLogger.setLoggingEnabled(true);
+        assertTrue(DailyNotificationLogger.isLoggingEnabled());
+    }
+    
+    @Test
+    public void testLogMessageFormat() {
+        String message = "Test message";
+        logger.log(message, DailyNotificationLogger.Level.INFO);
+        
+        // Note: Actual verification would require capturing log output
+    }
+    
+    @Test
+    public void testNullMessage() {
+        logger.log(null, DailyNotificationLogger.Level.INFO);
+        
+        // Note: Actual verification would require capturing log output
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationPluginTest.java b/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationPluginTest.java
new file mode 100644
index 0000000..98ee38c
--- /dev/null
+++ b/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationPluginTest.java
@@ -0,0 +1,227 @@
+/**
+ * DailyNotificationPluginTest.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Tests for the DailyNotification plugin
+ * 
+ * Features:
+ * - Unit tests
+ * - Integration tests
+ * - Edge cases
+ * - Error scenarios
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.os.PowerManager;
+import android.os.BatteryManager;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.getcapacitor.JSObject;
+import com.getcapacitor.PluginCall;
+import com.getcapacitor.PluginMethod;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+@RunWith(AndroidJUnit4.class)
+public class DailyNotificationPluginTest {
+    private DailyNotificationPlugin plugin;
+    private Context context;
+    private SharedPreferences settings;
+    
+    @Mock
+    private PluginCall mockCall;
+    
+    @Before
+    public void setUp() {
+        context = ApplicationProvider.getApplicationContext();
+        settings = context.getSharedPreferences("test_settings", Context.MODE_PRIVATE);
+        plugin = new DailyNotificationPlugin();
+        MockitoAnnotations.openMocks(this);
+    }
+    
+    @Test
+    public void testTimeValidation() {
+        // Valid time
+        assertTrue(plugin.isValidTime("09:00"));
+        assertTrue(plugin.isValidTime("00:00"));
+        assertTrue(plugin.isValidTime("23:59"));
+        
+        // Invalid times
+        assertFalse(plugin.isValidTime("24:00"));
+        assertFalse(plugin.isValidTime("12:60"));
+        assertFalse(plugin.isValidTime("9:00"));
+        assertFalse(plugin.isValidTime("13:5"));
+    }
+    
+    @Test
+    public void testTimezoneValidation() {
+        assertTrue(plugin.isValidTimezone("America/New_York"));
+        assertTrue(plugin.isValidTimezone("Europe/London"));
+        assertTrue(plugin.isValidTimezone("Asia/Kolkata"));
+        
+        assertFalse(plugin.isValidTimezone("Invalid/Timezone"));
+        assertFalse(plugin.isValidTimezone("America/Invalid"));
+    }
+    
+    @Test
+    public void testNotificationScheduling() {
+        when(mockCall.getString("url")).thenReturn("https://example.com");
+        when(mockCall.getString("time")).thenReturn("09:00");
+        when(mockCall.getString("title")).thenReturn("Test Notification");
+        when(mockCall.getString("body")).thenReturn("Test Body");
+        
+        plugin.scheduleDailyNotification(mockCall);
+        
+        // Verify notification was scheduled
+        // Note: Actual verification would require mocking AlarmManager
+    }
+    
+    @Test
+    public void testSettingsManagement() {
+        when(mockCall.hasOption("sound")).thenReturn(true);
+        when(mockCall.getBoolean("sound")).thenReturn(false);
+        when(mockCall.hasOption("priority")).thenReturn(true);
+        when(mockCall.getString("priority")).thenReturn("high");
+        
+        plugin.updateSettings(mockCall);
+        
+        // Verify settings were updated
+        assertEquals(false, settings.getBoolean("sound", true));
+        assertEquals("high", settings.getString("priority", "default"));
+    }
+    
+    @Test
+    public void testNotificationCancellation() {
+        plugin.cancelAllNotifications(mockCall);
+        
+        // Verify notifications were cancelled
+        // Note: Actual verification would require mocking NotificationManager
+    }
+    
+    @Test
+    public void testNotificationStatus() {
+        plugin.getNotificationStatus(mockCall);
+        
+        // Verify status was retrieved
+        // Note: Actual verification would require mocking NotificationManager
+    }
+    
+    @Test
+    public void testErrorHandling() {
+        when(mockCall.getString("url")).thenReturn(null);
+        when(mockCall.getString("time")).thenReturn(null);
+        
+        plugin.scheduleDailyNotification(mockCall);
+        
+        // Verify error was handled
+        verify(mockCall).reject(contains("Missing required parameters"));
+    }
+    
+    @Test
+    public void testBackgroundTaskHandling() {
+        // Test background task scheduling
+        // Note: Actual verification would require mocking WorkManager
+    }
+    
+    @Test
+    public void testBatteryOptimization() {
+        // Mock PowerManager
+        PowerManager mockPowerManager = mock(PowerManager.class);
+        when(context.getSystemService(Context.POWER_SERVICE)).thenReturn(mockPowerManager);
+        
+        // Test battery optimization exemption check
+        when(mockPowerManager.isIgnoringBatteryOptimizations(anyString())).thenReturn(true);
+        plugin.checkBatteryOptimization();
+        
+        // Test Doze mode detection
+        when(mockPowerManager.isDeviceIdleMode()).thenReturn(true);
+        assertTrue(plugin.isDeviceInDozeMode());
+        
+        // Test wake lock acquisition and release
+        PowerManager.WakeLock mockWakeLock = mock(PowerManager.WakeLock.class);
+        when(mockPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(mockWakeLock);
+        when(mockWakeLock.isHeld()).thenReturn(false);
+        
+        plugin.acquireWakeLock();
+        verify(mockWakeLock).acquire(anyLong());
+        
+        when(mockWakeLock.isHeld()).thenReturn(true);
+        plugin.releaseWakeLock();
+        verify(mockWakeLock).release();
+        
+        // Test battery optimization exemption request
+        PluginCall mockCall = mock(PluginCall.class);
+        plugin.requestBatteryOptimizationExemption(mockCall);
+        verify(context).startActivity(any(Intent.class));
+    }
+    
+    @Test
+    public void testNotificationChannelCreation() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            // Verify notification channel was created
+            // Note: Actual verification would require mocking NotificationManager
+        }
+    }
+    
+    @Test
+    public void testRetryLogic() {
+        // Test retry mechanism
+        // Note: Actual verification would require mocking network calls
+    }
+    
+    @Test
+    public void testEventHandling() {
+        // Test notification event handling
+        // Note: Actual verification would require mocking event system
+    }
+    
+    @Test
+    public void testResourceCleanup() {
+        // Test resource cleanup
+        // Note: Actual verification would require monitoring system resources
+    }
+    
+    @Test
+    public void testBatteryMonitoring() {
+        // Mock battery status intent
+        Intent batteryStatus = new Intent(Intent.ACTION_BATTERY_CHANGED);
+        batteryStatus.putExtra(BatteryManager.EXTRA_LEVEL, 75);
+        batteryStatus.putExtra(BatteryManager.EXTRA_SCALE, 100);
+        batteryStatus.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_HEALTH_CHARGING);
+        
+        // Send battery status broadcast
+        context.sendBroadcast(batteryStatus);
+        
+        // Verify battery status was updated
+        assertEquals(75, plugin.getBatteryLevel());
+        assertTrue(plugin.isCharging());
+        
+        // Test battery status retrieval
+        PluginCall mockCall = mock(PluginCall.class);
+        plugin.getBatteryStatus(mockCall);
+        verify(mockCall).resolve(any(JSObject.class));
+        
+        // Verify battery stats were stored
+        SharedPreferences prefs = context.getSharedPreferences(SETTINGS_KEY, Context.MODE_PRIVATE);
+        assertEquals(75, prefs.getInt("last_battery_level", -1));
+        assertTrue(prefs.getBoolean("last_charging_state", false));
+        assertTrue(prefs.getLong("last_battery_check", 0) > 0);
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationReceiverTest.java b/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationReceiverTest.java
new file mode 100644
index 0000000..0fe1193
--- /dev/null
+++ b/android/app/src/androidTest/java/com/timesafari/dailynotification/DailyNotificationReceiverTest.java
@@ -0,0 +1,102 @@
+/**
+ * DailyNotificationReceiverTest.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Tests for the DailyNotificationReceiver
+ * 
+ * Features:
+ * - Unit tests
+ * - Integration tests
+ * - Edge cases
+ * - Error scenarios
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+@RunWith(AndroidJUnit4.class)
+public class DailyNotificationReceiverTest {
+    private DailyNotificationReceiver receiver;
+    private Context context;
+    
+    @Before
+    public void setUp() {
+        context = ApplicationProvider.getApplicationContext();
+        receiver = new DailyNotificationReceiver();
+    }
+    
+    @Test
+    public void testValidNotificationData() {
+        Intent intent = new Intent();
+        intent.putExtra("url", "https://example.com");
+        intent.putExtra("title", "Test Notification");
+        intent.putExtra("body", "Test Body");
+        intent.putExtra("sound", true);
+        intent.putExtra("priority", "high");
+        
+        receiver.onReceive(context, intent);
+        
+        // Note: Actual verification would require mocking NotificationManager
+    }
+    
+    @Test
+    public void testMissingNotificationData() {
+        Intent intent = new Intent();
+        intent.putExtra("url", "https://example.com");
+        // Missing title and body
+        
+        receiver.onReceive(context, intent);
+        
+        // Note: Actual verification would require checking logs
+    }
+    
+    @Test
+    public void testInvalidPriority() {
+        Intent intent = new Intent();
+        intent.putExtra("url", "https://example.com");
+        intent.putExtra("title", "Test Notification");
+        intent.putExtra("body", "Test Body");
+        intent.putExtra("priority", "invalid");
+        
+        receiver.onReceive(context, intent);
+        
+        // Note: Actual verification would require checking logs
+    }
+    
+    @Test
+    public void testNotificationTap() {
+        Intent intent = new Intent();
+        intent.putExtra("url", "https://example.com");
+        intent.putExtra("title", "Test Notification");
+        intent.putExtra("body", "Test Body");
+        
+        // Note: Actual verification would require mocking PendingIntent
+    }
+    
+    @Test
+    public void testSoundSettings() {
+        Intent intent = new Intent();
+        intent.putExtra("url", "https://example.com");
+        intent.putExtra("title", "Test Notification");
+        intent.putExtra("body", "Test Body");
+        intent.putExtra("sound", false);
+        
+        receiver.onReceive(context, intent);
+        
+        // Note: Actual verification would require mocking NotificationManager
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 6379e55..13ff14c 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.timesafari.dailynotification">
 
     <uses-sdk android:minSdkVersion="22" android:targetSdkVersion="33" />
     
@@ -8,6 +9,14 @@
     <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
     <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
 
+    <!-- Battery optimization permissions -->
+    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    
+    <!-- Background task permissions -->
+    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+    <uses-permission android:name="android.permission.USE_EXACT_ALARM" />
+
     <application
         android:allowBackup="true"
         android:icon="@mipmap/ic_launcher"
diff --git a/android/app/src/main/java/com/timesafari/dailynotification/BatteryOptimizationSettings.java b/android/app/src/main/java/com/timesafari/dailynotification/BatteryOptimizationSettings.java
new file mode 100644
index 0000000..41c9afc
--- /dev/null
+++ b/android/app/src/main/java/com/timesafari/dailynotification/BatteryOptimizationSettings.java
@@ -0,0 +1,225 @@
+/**
+ * BatteryOptimizationSettings.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Manages battery optimization settings and power state monitoring
+ * 
+ * Features:
+ * - Battery optimization exemption management
+ * - Power state monitoring
+ * - Adaptive scheduling based on power state
+ * - Battery level monitoring
+ * - Doze mode handling
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.BatteryManager;
+import android.os.Build;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.content.SharedPreferences;
+
+import androidx.work.Constraints;
+import androidx.work.OneTimeWorkRequest;
+import androidx.work.WorkManager;
+
+import java.util.concurrent.TimeUnit;
+
+public class BatteryOptimizationSettings {
+    private static final String TAG = "BatteryOptimizationSettings";
+    private static final String BATTERY_OPTIMIZATION_KEY = "battery_optimization_exempt";
+    private static final String POWER_STATE_KEY = "power_state";
+    private static final String BATTERY_CHECK_INTERVAL = "battery_check_interval";
+    private static final long DEFAULT_CHECK_INTERVAL = TimeUnit.HOURS.toMillis(1);
+    
+    private final Context context;
+    private final PowerManager powerManager;
+    private final SharedPreferences settings;
+    private final DailyNotificationLogger logger;
+    
+    private boolean isOptimizationExempt = false;
+    private int powerState = PowerManager.POWER_STATE_NORMAL;
+    private int batteryLevel = 0;
+    private boolean isCharging = false;
+    private long lastBatteryCheck = 0;
+    
+    public BatteryOptimizationSettings(Context context, SharedPreferences settings) {
+        this.context = context;
+        this.settings = settings;
+        this.powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        this.logger = new DailyNotificationLogger();
+        
+        // Load saved state
+        isOptimizationExempt = settings.getBoolean(BATTERY_OPTIMIZATION_KEY, false);
+        powerState = settings.getInt(POWER_STATE_KEY, PowerManager.POWER_STATE_NORMAL);
+        lastBatteryCheck = settings.getLong(BATTERY_CHECK_INTERVAL, 0);
+    }
+    
+    public boolean requestBatteryOptimizationExemption() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            try {
+                // Check if already exempt
+                if (isOptimizationExempt) {
+                    logger.log("App already exempt from battery optimization", 
+                              DailyNotificationLogger.Level.INFO);
+                    return true;
+                }
+                
+                // Create intent for battery optimization settings
+                Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+                intent.setData(Uri.parse("package:" + context.getPackageName()));
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                
+                // Store request time
+                long requestTime = System.currentTimeMillis();
+                SharedPreferences.Editor editor = settings.edit();
+                editor.putLong("last_optimization_request", requestTime);
+                editor.apply();
+                
+                // Start settings activity
+                context.startActivity(intent);
+                
+                // Schedule a check for the optimization status
+                scheduleOptimizationCheck();
+                
+                logger.log("Battery optimization exemption requested", 
+                          DailyNotificationLogger.Level.INFO);
+                return true;
+            } catch (Exception e) {
+                logger.log("Error requesting battery optimization exemption: " + e.getMessage(), 
+                          DailyNotificationLogger.Level.ERROR);
+                return false;
+            }
+        }
+        return false;
+    }
+    
+    private void scheduleOptimizationCheck() {
+        OneTimeWorkRequest checkWork = new OneTimeWorkRequest.Builder(BatteryCheckWorker.class)
+            .setInitialDelay(5, TimeUnit.SECONDS)
+            .setConstraints(new Constraints.Builder()
+                .setRequiresBatteryNotLow(true)
+                .build())
+            .build();
+            
+        WorkManager.getInstance(context).enqueue(checkWork);
+    }
+    
+    public void updatePowerState() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            try {
+                int newPowerState = powerManager.getPowerState();
+                if (newPowerState != powerState) {
+                    powerState = newPowerState;
+                    SharedPreferences.Editor editor = settings.edit();
+                    editor.putInt(POWER_STATE_KEY, powerState);
+                    editor.apply();
+                    
+                    logger.log("Power state changed to: " + getPowerStateString(powerState), 
+                              DailyNotificationLogger.Level.INFO);
+                              
+                    adjustSchedulingForPowerState();
+                }
+            } catch (Exception e) {
+                logger.log("Error updating power state: " + e.getMessage(), 
+                          DailyNotificationLogger.Level.ERROR);
+            }
+        }
+    }
+    
+    public void updateBatteryStatus() {
+        try {
+            Intent batteryStatus = context.registerReceiver(null, 
+                new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+                
+            if (batteryStatus != null) {
+                int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+                int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+                float batteryPct = level * 100 / (float)scale;
+                
+                int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+                boolean charging = status == BatteryManager.BATTERY_HEALTH_CHARGING ||
+                                 status == BatteryManager.BATTERY_HEALTH_FULL;
+                
+                batteryLevel = (int)batteryPct;
+                isCharging = charging;
+                lastBatteryCheck = System.currentTimeMillis();
+                
+                // Store battery stats
+                SharedPreferences.Editor editor = settings.edit();
+                editor.putInt("last_battery_level", batteryLevel);
+                editor.putBoolean("last_charging_state", isCharging);
+                editor.putLong("last_battery_check", lastBatteryCheck);
+                editor.apply();
+                
+                logger.log(String.format("Battery status updated: %d%% (%s)", 
+                    batteryLevel, 
+                    isCharging ? "charging" : "not charging"),
+                    DailyNotificationLogger.Level.DEBUG);
+            }
+        } catch (Exception e) {
+            logger.log("Error updating battery status: " + e.getMessage(), 
+                      DailyNotificationLogger.Level.ERROR);
+        }
+    }
+    
+    private void adjustSchedulingForPowerState() {
+        switch (powerState) {
+            case PowerManager.POWER_STATE_SAVE:
+                // In power save mode, increase the interval between checks
+                lastBatteryCheck = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(2);
+                break;
+            case PowerManager.POWER_STATE_NORMAL:
+                // In normal mode, use standard intervals
+                lastBatteryCheck = System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(30);
+                break;
+            case PowerManager.POWER_STATE_OPTIMIZED:
+                // In optimized mode, use longer intervals
+                lastBatteryCheck = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(4);
+                break;
+        }
+    }
+    
+    private String getPowerStateString(int state) {
+        switch (state) {
+            case PowerManager.POWER_STATE_SAVE:
+                return "POWER_SAVE";
+            case PowerManager.POWER_STATE_NORMAL:
+                return "NORMAL";
+            case PowerManager.POWER_STATE_OPTIMIZED:
+                return "OPTIMIZED";
+            default:
+                return "UNKNOWN";
+        }
+    }
+    
+    public boolean isOptimizationExempt() {
+        return isOptimizationExempt;
+    }
+    
+    public int getPowerState() {
+        return powerState;
+    }
+    
+    public int getBatteryLevel() {
+        return batteryLevel;
+    }
+    
+    public boolean isCharging() {
+        return isCharging;
+    }
+    
+    public long getLastBatteryCheck() {
+        return lastBatteryCheck;
+    }
+    
+    public boolean shouldCheckBattery() {
+        return System.currentTimeMillis() - lastBatteryCheck > DEFAULT_CHECK_INTERVAL;
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationConfig.java b/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationConfig.java
new file mode 100644
index 0000000..c881f90
--- /dev/null
+++ b/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationConfig.java
@@ -0,0 +1,87 @@
+/**
+ * DailyNotificationConfig.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Configuration manager for the Daily Notification plugin
+ * 
+ * Features:
+ * - Singleton pattern
+ * - Configuration options
+ * - Default values
+ * - Settings persistence
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import java.util.TimeZone;
+
+public class DailyNotificationConfig {
+    private static DailyNotificationConfig instance;
+    
+    private int maxNotificationsPerDay;
+    private TimeZone defaultTimeZone;
+    private boolean loggingEnabled;
+    private int retentionDays;
+    
+    private DailyNotificationConfig() {
+        resetToDefaults();
+    }
+    
+    public static synchronized DailyNotificationConfig getInstance() {
+        if (instance == null) {
+            instance = new DailyNotificationConfig();
+        }
+        return instance;
+    }
+    
+    public void resetToDefaults() {
+        maxNotificationsPerDay = 10;
+        defaultTimeZone = TimeZone.getDefault();
+        loggingEnabled = true;
+        retentionDays = 7;
+    }
+    
+    public int getMaxNotificationsPerDay() {
+        return maxNotificationsPerDay;
+    }
+    
+    public void setMaxNotificationsPerDay(int maxNotificationsPerDay) {
+        if (maxNotificationsPerDay < 1) {
+            throw new IllegalArgumentException("Max notifications per day must be greater than 0");
+        }
+        this.maxNotificationsPerDay = maxNotificationsPerDay;
+    }
+    
+    public TimeZone getDefaultTimeZone() {
+        return defaultTimeZone;
+    }
+    
+    public void setDefaultTimeZone(TimeZone defaultTimeZone) {
+        if (defaultTimeZone == null) {
+            throw new IllegalArgumentException("Default timezone cannot be null");
+        }
+        this.defaultTimeZone = defaultTimeZone;
+    }
+    
+    public boolean isLoggingEnabled() {
+        return loggingEnabled;
+    }
+    
+    public void setLoggingEnabled(boolean loggingEnabled) {
+        this.loggingEnabled = loggingEnabled;
+        DailyNotificationLogger.setLoggingEnabled(loggingEnabled);
+    }
+    
+    public int getRetentionDays() {
+        return retentionDays;
+    }
+    
+    public void setRetentionDays(int retentionDays) {
+        if (retentionDays < 1) {
+            throw new IllegalArgumentException("Retention days must be greater than 0");
+        }
+        this.retentionDays = retentionDays;
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationConstants.java b/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationConstants.java
new file mode 100644
index 0000000..1389ef9
--- /dev/null
+++ b/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationConstants.java
@@ -0,0 +1,79 @@
+/**
+ * DailyNotificationConstants.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Constants used throughout the Daily Notification plugin
+ * 
+ * Features:
+ * - Default values
+ * - Notification identifiers
+ * - Settings keys
+ * - Channel settings
+ * - Time constants
+ * - Error messages
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+public class DailyNotificationConstants {
+    // Default values
+    public static final String DEFAULT_TITLE = "Daily Notification";
+    public static final String DEFAULT_BODY = "Your daily update is ready";
+    
+    // Notification identifiers
+    public static final String NOTIFICATION_ID_PREFIX = "daily-notification-";
+    public static final String EVENT_NAME = "notification";
+    
+    // Settings class
+    public static class Settings {
+        public static final String SOUND = "sound";
+        public static final String PRIORITY = "priority";
+        public static final String TIMEZONE = "timezone";
+        public static final String RETRY_COUNT = "retryCount";
+        public static final String RETRY_INTERVAL = "retryInterval";
+        
+        public static final boolean DEFAULT_SOUND = true;
+        public static final String DEFAULT_PRIORITY = "default";
+        public static final int DEFAULT_RETRY_COUNT = 3;
+        public static final int DEFAULT_RETRY_INTERVAL = 1000;
+    }
+    
+    // Plugin method keys
+    public static class Keys {
+        public static final String URL = "url";
+        public static final String TIME = "time";
+        public static final String TITLE = "title";
+        public static final String BODY = "body";
+        public static final String SOUND = "sound";
+        public static final String PRIORITY = "priority";
+        public static final String TIMEZONE = "timezone";
+    }
+    
+    // Channel settings
+    public static class Channel {
+        public static final String ID = "daily_notification_channel";
+        public static final String NAME = "Daily Notifications";
+        public static final String DESCRIPTION = "Daily notification updates";
+        public static final boolean ENABLE_VIBRATION = true;
+        public static final boolean ENABLE_LIGHTS = true;
+    }
+    
+    // Time constants
+    public static class Time {
+        public static final long MILLIS_PER_DAY = 86400000;
+        public static final int MAX_HOURS = 24;
+        public static final int MAX_MINUTES = 60;
+    }
+    
+    // Error messages
+    public static class Errors {
+        public static final String MISSING_PARAMS = "Missing required parameters";
+        public static final String INVALID_TIME = "Invalid time format";
+        public static final String INVALID_TIMEZONE = "Invalid timezone";
+        public static final String INVALID_PRIORITY = "Invalid priority value";
+        public static final String SCHEDULING_FAILED = "Failed to schedule notification";
+        public static final String PERMISSION_DENIED = "Notification permission denied";
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationLogger.java b/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationLogger.java
new file mode 100644
index 0000000..76d7bcd
--- /dev/null
+++ b/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationLogger.java
@@ -0,0 +1,92 @@
+/**
+ * DailyNotificationLogger.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Logging utility for the Daily Notification plugin
+ * 
+ * Features:
+ * - Log levels (DEBUG, INFO, WARNING, ERROR)
+ * - Throwable support
+ * - Enable/disable logging
+ * - Tag-based logging
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import android.util.Log;
+
+public class DailyNotificationLogger {
+    private static final String TAG = "DailyNotification";
+    private static boolean loggingEnabled = true;
+    
+    public enum Level {
+        DEBUG,
+        INFO,
+        WARNING,
+        ERROR
+    }
+    
+    public static void setLoggingEnabled(boolean enabled) {
+        loggingEnabled = enabled;
+    }
+    
+    public static boolean isLoggingEnabled() {
+        return loggingEnabled;
+    }
+    
+    public void log(String message, Level level) {
+        log(message, level, null);
+    }
+    
+    public void log(String message, Level level, Throwable throwable) {
+        if (!loggingEnabled) {
+            return;
+        }
+        
+        String formattedMessage = formatMessage(message);
+        
+        switch (level) {
+            case DEBUG:
+                if (throwable != null) {
+                    Log.d(TAG, formattedMessage, throwable);
+                } else {
+                    Log.d(TAG, formattedMessage);
+                }
+                break;
+                
+            case INFO:
+                if (throwable != null) {
+                    Log.i(TAG, formattedMessage, throwable);
+                } else {
+                    Log.i(TAG, formattedMessage);
+                }
+                break;
+                
+            case WARNING:
+                if (throwable != null) {
+                    Log.w(TAG, formattedMessage, throwable);
+                } else {
+                    Log.w(TAG, formattedMessage);
+                }
+                break;
+                
+            case ERROR:
+                if (throwable != null) {
+                    Log.e(TAG, formattedMessage, throwable);
+                } else {
+                    Log.e(TAG, formattedMessage);
+                }
+                break;
+        }
+    }
+    
+    private String formatMessage(String message) {
+        if (message == null) {
+            return "null";
+        }
+        
+        return String.format("[%s] %s", TAG, message);
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.java b/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.java
index 954a478..7bd6bca 100644
--- a/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.java
+++ b/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationPlugin.java
@@ -3,6 +3,16 @@
  * Daily Notification Plugin for Capacitor
  * 
  * Handles daily notification scheduling and management on Android
+ * 
+ * Features:
+ * - Daily notification scheduling with precise timing
+ * - Notification channel management
+ * - Settings persistence
+ * - Background task handling
+ * - Battery optimization support
+ * - Error handling and logging
+ * 
+ * @author Matthew Raymer
  */
 
 package com.timesafari.dailynotification;
@@ -11,12 +21,20 @@ import android.app.AlarmManager;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.SharedPreferences;
+import android.os.BatteryManager;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.PowerManager;
 import android.os.SystemClock;
+import android.provider.Settings;
+import android.util.Log;
 
 import com.getcapacitor.JSObject;
 import com.getcapacitor.Plugin;
@@ -26,26 +44,64 @@ import com.getcapacitor.annotation.CapacitorPlugin;
 
 import java.util.Calendar;
 import java.util.TimeZone;
+import java.util.concurrent.TimeUnit;
+
+import androidx.work.Constraints;
+import androidx.work.OneTimeWorkRequest;
+import androidx.work.WorkManager;
 
 @CapacitorPlugin(name = "DailyNotification")
 public class DailyNotificationPlugin extends Plugin {
+    private static final String TAG = "DailyNotificationPlugin";
     private static final String CHANNEL_ID = "daily_notification_channel";
     private static final String CHANNEL_NAME = "Daily Notifications";
     private static final String CHANNEL_DESCRIPTION = "Daily notification updates";
+    private static final String SETTINGS_KEY = "daily_notification_settings";
+    private static final String BATTERY_STATS_KEY = "battery_stats";
+    private static final String BATTERY_OPTIMIZATION_KEY = "battery_optimization_status";
+    private static final String BATTERY_CHECK_INTERVAL = "battery_check_interval";
+    private static final String LAST_NOTIFICATION_KEY = "last_notification_time";
+    private static final String POWER_STATE_KEY = "power_state";
+    private static final String ADAPTIVE_SCHEDULING_KEY = "adaptive_scheduling";
     
     private NotificationManager notificationManager;
     private AlarmManager alarmManager;
+    private PowerManager powerManager;
+    private PowerManager.WakeLock wakeLock;
     private Context context;
     private SharedPreferences settings;
-    private static final String SETTINGS_KEY = "daily_notification_settings";
+    private DailyNotificationLogger logger;
+    private boolean isOptimizationExempt = false;
+    private long lastBatteryCheck;
+    private int batteryLevel;
+    private boolean isCharging;
+    private long lastOptimizationCheck;
+    private boolean adaptiveSchedulingEnabled = true;
+    private int powerState = PowerManager.POWER_STATE_NORMAL;
     
     @Override
     public void load() {
         context = getContext();
         notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
-        createNotificationChannel();
+        powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         settings = context.getSharedPreferences(SETTINGS_KEY, Context.MODE_PRIVATE);
+        logger = new DailyNotificationLogger();
+        
+        createNotificationChannel();
+        initializeSettings();
+        checkBatteryOptimization();
+        initializeBatteryMonitoring();
+        logger.log("Plugin loaded successfully", DailyNotificationLogger.Level.INFO);
+    }
+    
+    private void initializeSettings() {
+        SharedPreferences.Editor editor = settings.edit();
+        if (!settings.contains("sound")) editor.putBoolean("sound", true);
+        if (!settings.contains("priority")) editor.putString("priority", "default");
+        if (!settings.contains("retryCount")) editor.putInt("retryCount", 3);
+        if (!settings.contains("retryInterval")) editor.putInt("retryInterval", 1000);
+        editor.apply();
     }
     
     private void createNotificationChannel() {
@@ -56,34 +112,204 @@ public class DailyNotificationPlugin extends Plugin {
                 NotificationManager.IMPORTANCE_DEFAULT
             );
             channel.setDescription(CHANNEL_DESCRIPTION);
+            channel.enableVibration(true);
+            channel.enableLights(true);
             notificationManager.createNotificationChannel(channel);
+            logger.log("Notification channel created", DailyNotificationLogger.Level.INFO);
+        }
+    }
+    
+    private void checkBatteryOptimization() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            String packageName = context.getPackageName();
+            isOptimizationExempt = powerManager.isIgnoringBatteryOptimizations(packageName);
+            lastOptimizationCheck = System.currentTimeMillis();
+            
+            // Store optimization status
+            SharedPreferences.Editor editor = settings.edit();
+            editor.putBoolean(BATTERY_OPTIMIZATION_KEY, isOptimizationExempt);
+            editor.putLong("last_optimization_check", lastOptimizationCheck);
+            editor.apply();
+            
+            logger.log("Battery optimization status: " + (isOptimizationExempt ? "exempt" : "not exempt"), 
+                      DailyNotificationLogger.Level.INFO);
+                      
+            // If not exempt and haven't checked recently, request exemption
+            if (!isOptimizationExempt && 
+                System.currentTimeMillis() - lastOptimizationCheck > BATTERY_CHECK_INTERVAL) {
+                requestBatteryOptimizationExemption(null);
+            }
         }
     }
     
     @PluginMethod
-    public void scheduleDailyNotification(PluginCall call) {
-        String url = call.getString("url");
-        String time = call.getString("time");
-        
-        if (url == null || time == null) {
-            call.reject("Missing required parameters");
-            return;
+    public void requestBatteryOptimizationExemption(PluginCall call) {
+        try {
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                // Check if we already have exemption
+                if (isOptimizationExempt) {
+                    logger.log("App already exempt from battery optimization", 
+                              DailyNotificationLogger.Level.INFO);
+                    if (call != null) {
+                        call.resolve();
+                    }
+                    return;
+                }
+
+                // Create intent for battery optimization settings
+                Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+                intent.setData(android.net.Uri.parse("package:" + context.getPackageName()));
+                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                
+                // Store current time for tracking
+                long requestTime = System.currentTimeMillis();
+                SharedPreferences.Editor editor = settings.edit();
+                editor.putLong("last_optimization_request", requestTime);
+                editor.apply();
+
+                // Start the activity
+                context.startActivity(intent);
+                
+                // Schedule a check for the optimization status after a delay
+                new Handler(Looper.getMainLooper()).postDelayed(() -> {
+                    checkBatteryOptimization();
+                    if (call != null) {
+                        JSObject result = new JSObject();
+                        result.put("isExempt", isOptimizationExempt);
+                        result.put("requestTime", requestTime);
+                        result.put("checkTime", System.currentTimeMillis());
+                        call.resolve(result);
+                    }
+                }, 5000); // Check after 5 seconds
+                
+                logger.log("Battery optimization exemption requested", 
+                          DailyNotificationLogger.Level.INFO);
+            } else {
+                if (call != null) {
+                    call.reject("Battery optimization exemption not supported on this Android version");
+                }
+            }
+        } catch (Exception e) {
+            logger.log("Error requesting battery optimization exemption: " + e.getMessage(), 
+                      DailyNotificationLogger.Level.ERROR);
+            if (call != null) {
+                call.reject("Failed to request battery optimization exemption: " + e.getMessage());
+            }
         }
-        
-        // Parse time string (HH:mm format)
-        String[] timeComponents = time.split(":");
-        if (timeComponents.length != 2) {
-            call.reject("Invalid time format");
-            return;
+    }
+    
+    private void acquireWakeLock() {
+        if (wakeLock == null) {
+            wakeLock = powerManager.newWakeLock(
+                PowerManager.PARTIAL_WAKE_LOCK,
+                "DailyNotification:WakeLock"
+            );
         }
-        
+
+        if (!wakeLock.isHeld()) {
+            // Adjust wake lock duration based on battery level
+            long duration = TimeUnit.MINUTES.toMillis(1);
+            if (batteryLevel < 15) {
+                duration = TimeUnit.SECONDS.toMillis(30);
+            } else if (batteryLevel < 30) {
+                duration = TimeUnit.SECONDS.toMillis(45);
+            }
+            
+            wakeLock.acquire(duration);
+            logger.log("Wake lock acquired for " + duration + "ms", DailyNotificationLogger.Level.DEBUG);
+        }
+    }
+    
+    private void releaseWakeLock() {
+        if (wakeLock != null && wakeLock.isHeld()) {
+            wakeLock.release();
+            logger.log("Wake lock released", DailyNotificationLogger.Level.DEBUG);
+        }
+    }
+    
+    private boolean isDeviceInDozeMode() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            return powerManager.isDeviceIdleMode();
+        }
+        return false;
+    }
+    
+    private void handleDozeMode() {
+        if (isDeviceInDozeMode()) {
+            logger.log("Device is in Doze mode", DailyNotificationLogger.Level.WARNING);
+            
+            // If not exempt from battery optimization, try to request exemption
+            if (!isOptimizationExempt) {
+                requestBatteryOptimizationExemption(null);
+            }
+            
+            // Schedule a maintenance window for the next time the device exits Doze mode
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+                // Use WorkManager for more reliable scheduling during Doze
+                OneTimeWorkRequest maintenanceWork = new OneTimeWorkRequest.Builder(MaintenanceWorker.class)
+                    .setInitialDelay(15, TimeUnit.MINUTES)
+                    .setConstraints(new Constraints.Builder()
+                        .setRequiresDeviceIdle(false)
+                        .setRequiresBatteryNotLow(true)
+                        .build())
+                    .build();
+                    
+                WorkManager.getInstance(context).enqueue(maintenanceWork);
+                
+                // Also set an alarm as backup
+                alarmManager.setAndAllowWhileIdle(
+                    AlarmManager.RTC_WAKEUP,
+                    System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(15),
+                    createMaintenancePendingIntent()
+                );
+            }
+        }
+    }
+    
+    private PendingIntent createMaintenancePendingIntent() {
+        Intent intent = new Intent(context, DailyNotificationReceiver.class);
+        intent.setAction("MAINTENANCE_WINDOW");
+        return PendingIntent.getBroadcast(
+            context,
+            0,
+            intent,
+            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
+        );
+    }
+    
+    @PluginMethod
+    public void scheduleDailyNotification(PluginCall call) {
         try {
+            // Check battery optimization status
+            if (!isOptimizationExempt) {
+                logger.log("Warning: App is not exempt from battery optimization", 
+                          DailyNotificationLogger.Level.WARNING);
+            }
+            
+            // Check Doze mode
+            handleDozeMode();
+            
+            // Acquire wake lock for scheduling
+            acquireWakeLock();
+            
+            String url = call.getString("url");
+            String time = call.getString("time");
+            
+            if (url == null || time == null) {
+                throw new IllegalArgumentException("Missing required parameters");
+            }
+            
+            // Parse time string (HH:mm format)
+            String[] timeComponents = time.split(":");
+            if (timeComponents.length != 2) {
+                throw new IllegalArgumentException("Invalid time format");
+            }
+            
             int hour = Integer.parseInt(timeComponents[0]);
             int minute = Integer.parseInt(timeComponents[1]);
             
             if (hour < 0 || hour >= 24 || minute < 0 || minute >= 60) {
-                call.reject("Invalid time values");
-                return;
+                throw new IllegalArgumentException("Invalid time values");
             }
             
             // Create calendar instance for the specified time
@@ -102,6 +328,8 @@ public class DailyNotificationPlugin extends Plugin {
             intent.putExtra("url", url);
             intent.putExtra("title", call.getString("title", "Daily Notification"));
             intent.putExtra("body", call.getString("body", "Your daily update is ready"));
+            intent.putExtra("sound", call.getBoolean("sound", settings.getBoolean("sound", true)));
+            intent.putExtra("priority", call.getString("priority", settings.getString("priority", "default")));
             
             PendingIntent pendingIntent = PendingIntent.getBroadcast(
                 context,
@@ -110,66 +338,399 @@ public class DailyNotificationPlugin extends Plugin {
                 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
             );
             
-            // Schedule the alarm
+            // Schedule the alarm with exact timing
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                if (alarmManager.canScheduleExactAlarms()) {
+                    alarmManager.setExactAndAllowWhileIdle(
+                        AlarmManager.RTC_WAKEUP,
+                        calendar.getTimeInMillis(),
+                        pendingIntent
+                    );
+                } else {
+                    throw new SecurityException("Cannot schedule exact alarms");
+                }
+            } else {
+                alarmManager.setExactAndAllowWhileIdle(
+                    AlarmManager.RTC_WAKEUP,
+                    calendar.getTimeInMillis(),
+                    pendingIntent
+                );
+            }
+            
+            // Set repeating alarm for subsequent days
             alarmManager.setRepeating(
                 AlarmManager.RTC_WAKEUP,
-                calendar.getTimeInMillis(),
-                AlarmManager.INTERVAL_DAY,
+                calendar.getTimeInMillis() + TimeUnit.DAYS.toMillis(1),
+                TimeUnit.DAYS.toMillis(1),
                 pendingIntent
             );
             
+            // Release wake lock after scheduling
+            releaseWakeLock();
+            
+            // Store the scheduled time and URL for potential rescheduling
+            SharedPreferences.Editor editor = settings.edit();
+            editor.putString("scheduled_time", time);
+            editor.putString("notification_url", url);
+            editor.putString("notification_title", call.getString("title", "Daily Notification"));
+            editor.putString("notification_body", call.getString("body", "Your daily update is ready"));
+            editor.apply();
+            
+            logger.log("Notification scheduled for " + time, DailyNotificationLogger.Level.INFO);
             call.resolve();
-        } catch (NumberFormatException e) {
-            call.reject("Invalid time format");
+            
+        } catch (Exception e) {
+            releaseWakeLock();
+            logger.log("Error scheduling notification: " + e.getMessage(), DailyNotificationLogger.Level.ERROR);
+            call.reject("Failed to schedule notification: " + e.getMessage());
         }
     }
     
     @PluginMethod
     public void getLastNotification(PluginCall call) {
-        // TODO: Implement last notification retrieval
-        JSObject result = new JSObject();
-        result.put("id", "");
-        result.put("title", "");
-        result.put("body", "");
-        result.put("timestamp", 0);
-        call.resolve(result);
+        try {
+            // TODO: Implement last notification retrieval from local storage
+            JSObject result = new JSObject();
+            result.put("id", "");
+            result.put("title", "");
+            result.put("body", "");
+            result.put("timestamp", 0);
+            call.resolve(result);
+        } catch (Exception e) {
+            logger.log("Error getting last notification: " + e.getMessage(), DailyNotificationLogger.Level.ERROR);
+            call.reject("Failed to get last notification: " + e.getMessage());
+        }
     }
     
     @PluginMethod
     public void cancelAllNotifications(PluginCall call) {
-        Intent intent = new Intent(context, DailyNotificationReceiver.class);
-        PendingIntent pendingIntent = PendingIntent.getBroadcast(
-            context,
-            0,
-            intent,
-            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
-        );
-        alarmManager.cancel(pendingIntent);
-        call.resolve();
+        try {
+            Intent intent = new Intent(context, DailyNotificationReceiver.class);
+            PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                context,
+                0,
+                intent,
+                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
+            );
+            alarmManager.cancel(pendingIntent);
+            notificationManager.cancelAll();
+            logger.log("All notifications cancelled", DailyNotificationLogger.Level.INFO);
+            call.resolve();
+        } catch (Exception e) {
+            logger.log("Error cancelling notifications: " + e.getMessage(), DailyNotificationLogger.Level.ERROR);
+            call.reject("Failed to cancel notifications: " + e.getMessage());
+        }
     }
     
     @PluginMethod
     public void getNotificationStatus(PluginCall call) {
-        JSObject result = new JSObject();
-        result.put("nextNotificationTime", 0); // TODO: Implement next notification time
-        result.put("isEnabled", true); // TODO: Check system notification settings
-        call.resolve(result);
+        try {
+            JSObject result = new JSObject();
+            result.put("nextNotificationTime", getNextNotificationTime());
+            result.put("isEnabled", isNotificationEnabled());
+            result.put("settings", getCurrentSettings());
+            call.resolve(result);
+        } catch (Exception e) {
+            logger.log("Error getting notification status: " + e.getMessage(), DailyNotificationLogger.Level.ERROR);
+            call.reject("Failed to get notification status: " + e.getMessage());
+        }
     }
     
     @PluginMethod
     public void updateSettings(PluginCall call) {
-        SharedPreferences.Editor editor = settings.edit();
-        if (call.hasOption("timezone")) {
-            String timezone = call.getString("timezone");
-            if (TimeZone.getTimeZone(timezone) != null) {
-                editor.putString("timezone", timezone);
-            } else {
-                call.reject("Invalid timezone");
-                return;
+        try {
+            SharedPreferences.Editor editor = settings.edit();
+            
+            if (call.hasOption("sound")) {
+                editor.putBoolean("sound", call.getBoolean("sound"));
+            }
+            
+            if (call.hasOption("priority")) {
+                String priority = call.getString("priority");
+                if (isValidPriority(priority)) {
+                    editor.putString("priority", priority);
+                } else {
+                    throw new IllegalArgumentException("Invalid priority value");
+                }
             }
+            
+            if (call.hasOption("timezone")) {
+                String timezone = call.getString("timezone");
+                if (TimeZone.getTimeZone(timezone) != null) {
+                    editor.putString("timezone", timezone);
+                } else {
+                    throw new IllegalArgumentException("Invalid timezone");
+                }
+            }
+            
+            editor.apply();
+            logger.log("Settings updated successfully", DailyNotificationLogger.Level.INFO);
+            call.resolve(getCurrentSettings());
+        } catch (Exception e) {
+            logger.log("Error updating settings: " + e.getMessage(), DailyNotificationLogger.Level.ERROR);
+            call.reject("Failed to update settings: " + e.getMessage());
+        }
+    }
+    
+    private long getNextNotificationTime() {
+        // TODO: Implement next notification time retrieval
+        return 0;
+    }
+    
+    private boolean isNotificationEnabled() {
+        return notificationManager.areNotificationsEnabled();
+    }
+    
+    private JSObject getCurrentSettings() {
+        JSObject settings = new JSObject();
+        settings.put("sound", this.settings.getBoolean("sound", true));
+        settings.put("priority", this.settings.getString("priority", "default"));
+        settings.put("timezone", this.settings.getString("timezone", TimeZone.getDefault().getID()));
+        return settings;
+    }
+    
+    private boolean isValidPriority(String priority) {
+        return priority != null && 
+               (priority.equals("high") || 
+                priority.equals("default") || 
+                priority.equals("low"));
+    }
+    
+    private void initializeBatteryMonitoring() {
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+        filter.addAction(Intent.ACTION_POWER_CONNECTED);
+        filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
+        filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+        context.registerReceiver(batteryReceiver, filter);
+        updateBatteryStatus();
+        updatePowerState();
+    }
+    
+    private final BroadcastReceiver batteryReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            updateBatteryStatus();
+        }
+    };
+    
+    private void updateBatteryStatus() {
+        Intent batteryStatus = context.registerReceiver(null, 
+            new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
+            
+        if (batteryStatus != null) {
+            int level = batteryStatus.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+            int scale = batteryStatus.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
+            float batteryPct = level * 100 / (float)scale;
+            
+            int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
+            boolean charging = status == BatteryManager.BATTERY_HEALTH_CHARGING ||
+                             status == BatteryManager.BATTERY_HEALTH_FULL;
+            
+            batteryLevel = (int)batteryPct;
+            isCharging = charging;
+            lastBatteryCheck = System.currentTimeMillis();
+            
+            logger.log(String.format("Battery status updated: %d%% (%s)", 
+                batteryLevel, 
+                isCharging ? "charging" : "not charging"),
+                DailyNotificationLogger.Level.DEBUG);
+                
+            // Store battery stats
+            SharedPreferences.Editor editor = settings.edit();
+            editor.putInt("last_battery_level", batteryLevel);
+            editor.putBoolean("last_charging_state", isCharging);
+            editor.putLong("last_battery_check", lastBatteryCheck);
+            editor.apply();
+            
+            // Adjust scheduling based on battery level if adaptive scheduling is enabled
+            if (adaptiveSchedulingEnabled) {
+                adjustSchedulingForBatteryLevel();
+            }
+        }
+    }
+    
+    private void adjustSchedulingForBatteryLevel() {
+        if (batteryLevel < 15) {
+            // Critical battery level - reduce frequency
+            lastBatteryCheck = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(4);
+        } else if (batteryLevel < 30) {
+            // Low battery level - moderate frequency
+            lastBatteryCheck = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(2);
+        } else if (batteryLevel < 50) {
+            // Medium battery level - standard frequency
+            lastBatteryCheck = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(1);
+        }
+    }
+    
+    private void updatePowerState() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            powerState = powerManager.getPowerState();
+            SharedPreferences.Editor editor = settings.edit();
+            editor.putInt(POWER_STATE_KEY, powerState);
+            editor.apply();
+            
+            // Adjust scheduling based on power state
+            if (adaptiveSchedulingEnabled) {
+                adjustSchedulingForPowerState();
+            }
+        }
+    }
+    
+    private void adjustSchedulingForPowerState() {
+        if (powerState == PowerManager.POWER_STATE_SAVE) {
+            // In power save mode, increase the interval between checks
+            lastBatteryCheck = System.currentTimeMillis() - TimeUnit.HOURS.toMillis(2);
+        } else if (powerState == PowerManager.POWER_STATE_NORMAL) {
+            // In normal mode, use standard intervals
+            lastBatteryCheck = System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(30);
+        }
+    }
+    
+    @PluginMethod
+    public void getBatteryStatus(PluginCall call) {
+        try {
+            // Check battery optimization status if needed
+            if (System.currentTimeMillis() - lastOptimizationCheck > BATTERY_CHECK_INTERVAL) {
+                checkBatteryOptimization();
+            }
+            
+            JSObject result = new JSObject();
+            result.put("level", batteryLevel);
+            result.put("isCharging", isCharging);
+            result.put("lastCheck", lastBatteryCheck);
+            result.put("isOptimizationExempt", isOptimizationExempt);
+            result.put("lastOptimizationCheck", lastOptimizationCheck);
+            result.put("isInDozeMode", isDeviceInDozeMode());
+            call.resolve(result);
+        } catch (Exception e) {
+            logger.log("Error getting battery status: " + e.getMessage(), 
+                      DailyNotificationLogger.Level.ERROR);
+            call.reject("Failed to get battery status: " + e.getMessage());
+        }
+    }
+    
+    @Override
+    protected void handleOnDestroy() {
+        try {
+            context.unregisterReceiver(batteryReceiver);
+        } catch (Exception e) {
+            logger.log("Error unregistering battery receiver: " + e.getMessage(), 
+                      DailyNotificationLogger.Level.ERROR);
+        }
+        super.handleOnDestroy();
+    }
+    
+    public void rescheduleMissedNotifications() {
+        try {
+            long lastNotificationTime = settings.getLong(LAST_NOTIFICATION_KEY, 0);
+            long currentTime = System.currentTimeMillis();
+            
+            // If more than 24 hours have passed since the last notification
+            if (currentTime - lastNotificationTime > TimeUnit.DAYS.toMillis(1)) {
+                logger.log("Missed notifications detected, rescheduling", DailyNotificationLogger.Level.WARNING);
+                
+                // Get the scheduled time from settings
+                String scheduledTime = settings.getString("scheduled_time", null);
+                if (scheduledTime != null) {
+                    // Parse the scheduled time
+                    String[] timeComponents = scheduledTime.split(":");
+                    if (timeComponents.length == 2) {
+                        int hour = Integer.parseInt(timeComponents[0]);
+                        int minute = Integer.parseInt(timeComponents[1]);
+                        
+                        // Create calendar instance for the scheduled time
+                        Calendar calendar = Calendar.getInstance();
+                        calendar.set(Calendar.HOUR_OF_DAY, hour);
+                        calendar.set(Calendar.MINUTE, minute);
+                        calendar.set(Calendar.SECOND, 0);
+                        
+                        // If the time has already passed today, schedule for tomorrow
+                        if (calendar.getTimeInMillis() <= currentTime) {
+                            calendar.add(Calendar.DAY_OF_YEAR, 1);
+                        }
+                        
+                        // Get the notification URL from settings
+                        String url = settings.getString("notification_url", null);
+                        if (url != null) {
+                            // Create intent for the notification
+                            Intent intent = new Intent(context, DailyNotificationReceiver.class);
+                            intent.putExtra("url", url);
+                            intent.putExtra("title", settings.getString("notification_title", "Daily Notification"));
+                            intent.putExtra("body", settings.getString("notification_body", "Your daily update is ready"));
+                            intent.putExtra("sound", settings.getBoolean("sound", true));
+                            intent.putExtra("priority", settings.getString("priority", "default"));
+                            
+                            PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                                context,
+                                url.hashCode(),
+                                intent,
+                                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
+                            );
+                            
+                            // Schedule the notification
+                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+                                if (alarmManager.canScheduleExactAlarms()) {
+                                    alarmManager.setExactAndAllowWhileIdle(
+                                        AlarmManager.RTC_WAKEUP,
+                                        calendar.getTimeInMillis(),
+                                        pendingIntent
+                                    );
+                                }
+                            } else {
+                                alarmManager.setExactAndAllowWhileIdle(
+                                    AlarmManager.RTC_WAKEUP,
+                                    calendar.getTimeInMillis(),
+                                    pendingIntent
+                                );
+                            }
+                            
+                            logger.log("Missed notification rescheduled for " + scheduledTime, 
+                                      DailyNotificationLogger.Level.INFO);
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.log("Error rescheduling missed notifications: " + e.getMessage(), 
+                      DailyNotificationLogger.Level.ERROR);
+        }
+    }
+    
+    @PluginMethod
+    public void setAdaptiveScheduling(PluginCall call) {
+        try {
+            boolean enabled = call.getBoolean("enabled", true);
+            adaptiveSchedulingEnabled = enabled;
+            
+            SharedPreferences.Editor editor = settings.edit();
+            editor.putBoolean(ADAPTIVE_SCHEDULING_KEY, enabled);
+            editor.apply();
+            
+            logger.log("Adaptive scheduling " + (enabled ? "enabled" : "disabled"), 
+                      DailyNotificationLogger.Level.INFO);
+            call.resolve();
+        } catch (Exception e) {
+            logger.log("Error setting adaptive scheduling: " + e.getMessage(), 
+                      DailyNotificationLogger.Level.ERROR);
+            call.reject("Failed to set adaptive scheduling: " + e.getMessage());
+        }
+    }
+    
+    @PluginMethod
+    public void getPowerState(PluginCall call) {
+        try {
+            JSObject result = new JSObject();
+            result.put("powerState", powerState);
+            result.put("adaptiveScheduling", adaptiveSchedulingEnabled);
+            result.put("batteryLevel", batteryLevel);
+            result.put("isCharging", isCharging);
+            result.put("lastCheck", lastBatteryCheck);
+            call.resolve(result);
+        } catch (Exception e) {
+            logger.log("Error getting power state: " + e.getMessage(), 
+                      DailyNotificationLogger.Level.ERROR);
+            call.reject("Failed to get power state: " + e.getMessage());
         }
-        // Add other settings...
-        editor.apply();
-        call.resolve();
     }
 } 
\ No newline at end of file
diff --git a/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationReceiver.java b/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationReceiver.java
index d7de652..0a7d05b 100644
--- a/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationReceiver.java
+++ b/android/app/src/main/java/com/timesafari/dailynotification/DailyNotificationReceiver.java
@@ -1,51 +1,186 @@
 /**
  * DailyNotificationReceiver.java
- * Broadcast receiver for handling daily notifications on Android
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Broadcast receiver for handling daily notifications
+ * 
+ * Features:
+ * - Notification display with custom actions
+ * - Rich notification content
+ * - Event broadcasting
+ * - Error recovery
+ * - Notification categories
+ * 
+ * @author Matthew Raymer
  */
 
 package com.timesafari.dailynotification;
 
+import android.app.Notification;
+import android.app.NotificationChannel;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Build;
+import android.os.Bundle;
 
 import androidx.core.app.NotificationCompat;
+import androidx.core.app.NotificationManagerCompat;
 
 public class DailyNotificationReceiver extends BroadcastReceiver {
-    private static final String CHANNEL_ID = "daily_notification_channel";
+    private static final String TAG = "DailyNotificationReceiver";
+    private DailyNotificationLogger logger;
+
+    // Notification categories
+    private static final String CATEGORY_DAILY = "DAILY_NOTIFICATION";
     
+    // Action identifiers
+    private static final String ACTION_VIEW = "VIEW";
+    private static final String ACTION_DISMISS = "DISMISS";
+    private static final String ACTION_SNOOZE = "SNOOZE";
+
     @Override
     public void onReceive(Context context, Intent intent) {
-        String url = intent.getStringExtra("url");
-        String title = intent.getStringExtra("title");
-        String body = intent.getStringExtra("body");
+        logger = new DailyNotificationLogger();
         
-        if (url == null || title == null || body == null) {
-            return;
+        try {
+            String url = intent.getStringExtra("url");
+            String title = intent.getStringExtra("title");
+            String body = intent.getStringExtra("body");
+            boolean sound = intent.getBooleanExtra("sound", true);
+            String priority = intent.getStringExtra("priority");
+            
+            if (url == null || title == null || body == null) {
+                throw new IllegalArgumentException("Missing required notification parameters");
+            }
+            
+            showNotification(context, title, body, url, sound, priority);
+            logger.log("Notification displayed successfully", DailyNotificationLogger.Level.INFO);
+            
+        } catch (Exception e) {
+            logger.log("Error displaying notification: " + e.getMessage(), 
+                      DailyNotificationLogger.Level.ERROR, e);
         }
-        
-        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_ID)
-            .setSmallIcon(android.R.drawable.ic_dialog_info)
-            .setContentTitle(title)
-            .setContentText(body)
-            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
-            .setAutoCancel(true);
-        
+    }
+    
+    private void showNotification(Context context, String title, String body, 
+                                String url, boolean sound, String priority) {
         NotificationManager notificationManager = 
             (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
             
+        // Create notification channel if needed
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
-            notificationManager.createNotificationChannel(
-                new android.app.NotificationChannel(
-                    CHANNEL_ID,
-                    "Daily Notifications",
-                    NotificationManager.IMPORTANCE_DEFAULT
-                )
+            NotificationChannel channel = new NotificationChannel(
+                DailyNotificationConstants.Channel.ID,
+                DailyNotificationConstants.Channel.NAME,
+                NotificationManager.IMPORTANCE_DEFAULT
             );
+            channel.setDescription(DailyNotificationConstants.Channel.DESCRIPTION);
+            channel.enableVibration(DailyNotificationConstants.Channel.ENABLE_VIBRATION);
+            channel.enableLights(DailyNotificationConstants.Channel.ENABLE_LIGHTS);
+            notificationManager.createNotificationChannel(channel);
+        }
+            
+        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, 
+            DailyNotificationConstants.Channel.ID)
+            .setSmallIcon(android.R.drawable.ic_dialog_info)
+            .setContentTitle(title)
+            .setContentText(body)
+            .setPriority(getNotificationPriority(priority))
+            .setCategory(CATEGORY_DAILY)
+            .setAutoCancel(true)
+            .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
+            .setStyle(new NotificationCompat.BigTextStyle().bigText(body));
+            
+        if (sound) {
+            builder.setDefaults(NotificationCompat.DEFAULT_SOUND);
+        }
+        
+        // Create intent for notification tap
+        Intent contentIntent = new Intent(context, context.getClass());
+        contentIntent.setData(Uri.parse(url));
+        
+        PendingIntent pendingIntent = PendingIntent.getActivity(
+            context,
+            0,
+            contentIntent,
+            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
+        );
+        
+        builder.setContentIntent(pendingIntent);
+        
+        // Add custom actions
+        addCustomActions(builder, context, url);
+        
+        Notification notification = builder.build();
+        
+        // Use NotificationManagerCompat for better compatibility
+        NotificationManagerCompat notificationManagerCompat = 
+            NotificationManagerCompat.from(context);
+            
+        try {
+            notificationManagerCompat.notify(url.hashCode(), notification);
+        } catch (SecurityException e) {
+            logger.log("Security exception while showing notification: " + e.getMessage(),
+                      DailyNotificationLogger.Level.ERROR);
         }
+    }
+    
+    private void addCustomActions(NotificationCompat.Builder builder, Context context, String url) {
+        // View action
+        Intent viewIntent = new Intent(context, context.getClass());
+        viewIntent.setAction(ACTION_VIEW);
+        viewIntent.setData(Uri.parse(url));
+        
+        PendingIntent viewPendingIntent = PendingIntent.getActivity(
+            context,
+            1,
+            viewIntent,
+            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
+        );
         
-        notificationManager.notify(url.hashCode(), builder.build());
+        builder.addAction(android.R.drawable.ic_menu_view, "View", viewPendingIntent);
+        
+        // Snooze action
+        Intent snoozeIntent = new Intent(context, context.getClass());
+        snoozeIntent.setAction(ACTION_SNOOZE);
+        snoozeIntent.putExtra("url", url);
+        
+        PendingIntent snoozePendingIntent = PendingIntent.getBroadcast(
+            context,
+            2,
+            snoozeIntent,
+            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
+        );
+        
+        builder.addAction(android.R.drawable.ic_menu_revert, "Snooze", snoozePendingIntent);
+        
+        // Dismiss action
+        Intent dismissIntent = new Intent(context, context.getClass());
+        dismissIntent.setAction(ACTION_DISMISS);
+        dismissIntent.putExtra("url", url);
+        
+        PendingIntent dismissPendingIntent = PendingIntent.getBroadcast(
+            context,
+            3,
+            dismissIntent,
+            PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
+        );
+        
+        builder.addAction(android.R.drawable.ic_menu_close_clear_cancel, "Dismiss", dismissPendingIntent);
+    }
+    
+    private int getNotificationPriority(String priority) {
+        switch (priority.toLowerCase()) {
+            case "high":
+                return NotificationCompat.PRIORITY_HIGH;
+            case "low":
+                return NotificationCompat.PRIORITY_LOW;
+            default:
+                return NotificationCompat.PRIORITY_DEFAULT;
+        }
     }
 } 
\ No newline at end of file
diff --git a/android/app/src/main/java/com/timesafari/dailynotification/MaintenanceWorker.java b/android/app/src/main/java/com/timesafari/dailynotification/MaintenanceWorker.java
new file mode 100644
index 0000000..e6b0c07
--- /dev/null
+++ b/android/app/src/main/java/com/timesafari/dailynotification/MaintenanceWorker.java
@@ -0,0 +1,51 @@
+package com.timesafari.dailynotification;
+
+import android.content.Context;
+import androidx.annotation.NonNull;
+import androidx.work.Worker;
+import androidx.work.WorkerParameters;
+
+public class MaintenanceWorker extends Worker {
+    private final DailyNotificationLogger logger;
+    
+    public MaintenanceWorker(@NonNull Context context, @NonNull WorkerParameters params) {
+        super(context, params);
+        logger = new DailyNotificationLogger();
+    }
+    
+    @NonNull
+    @Override
+    public Result doWork() {
+        try {
+            logger.log("Maintenance work started", DailyNotificationLogger.Level.INFO);
+            
+            // Perform maintenance tasks
+            performMaintenance();
+            
+            logger.log("Maintenance work completed successfully", DailyNotificationLogger.Level.INFO);
+            return Result.success();
+        } catch (Exception e) {
+            logger.log("Error during maintenance work: " + e.getMessage(), 
+                      DailyNotificationLogger.Level.ERROR);
+            return Result.failure();
+        }
+    }
+    
+    private void performMaintenance() {
+        // Check and update battery optimization status
+        DailyNotificationPlugin plugin = DailyNotificationPlugin.getInstance();
+        if (plugin != null) {
+            plugin.checkBatteryOptimization();
+        }
+        
+        // Update battery status
+        if (plugin != null) {
+            plugin.updateBatteryStatus();
+        }
+        
+        // Reschedule any missed notifications
+        if (plugin != null) {
+            plugin.rescheduleMissedNotifications();
+        }
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/main/java/com/timesafari/dailynotification/README.md b/android/app/src/main/java/com/timesafari/dailynotification/README.md
new file mode 100644
index 0000000..e58d875
--- /dev/null
+++ b/android/app/src/main/java/com/timesafari/dailynotification/README.md
@@ -0,0 +1,423 @@
+# DailyNotification Android Implementation
+
+This directory contains the Android-specific implementation of the DailyNotification plugin for Capacitor.
+
+## Overview
+
+The DailyNotification plugin provides functionality for scheduling and managing daily notifications on Android devices. It uses Android's native notification system and background task scheduling to ensure reliable delivery of notifications.
+
+## Features
+
+- Daily notification scheduling with precise timing
+- Notification channel management (Android 8.0+)
+- Background task handling with WorkManager
+- Battery optimization support
+- Settings persistence
+- Rich logging capabilities
+- Comprehensive error handling
+- Extensive test coverage
+
+## Architecture
+
+### Core Components
+
+1. **DailyNotificationPlugin**
+   - Main plugin class handling all notification operations
+   - Manages notification scheduling and settings
+   - Handles plugin method calls from JavaScript
+
+2. **DailyNotificationReceiver**
+   - Broadcast receiver for handling notification display
+   - Manages notification content and presentation
+
+3. **DailyNotificationLogger**
+   - Structured logging system
+   - Multiple log levels (DEBUG, INFO, WARNING, ERROR)
+   - Configurable logging behavior
+
+4. **DailyNotificationConstants**
+   - Centralized constants management
+   - Default values and configuration
+   - Error messages and keys
+
+5. **DailyNotificationConfig**
+   - Configuration management
+   - Settings persistence
+   - Default values
+
+### Key Features
+
+#### Notification Scheduling
+- Uses AlarmManager for precise timing
+- Handles timezone changes
+- Supports multiple notifications per day
+- Battery-optimized scheduling
+
+#### Background Processing
+- WorkManager for reliable background tasks
+- Battery optimization handling
+- Network state monitoring
+- Retry mechanism
+
+#### Settings Management
+- Persistent storage using SharedPreferences
+- Default values management
+- Settings validation
+- Real-time updates
+
+#### Error Handling
+- Comprehensive error catching
+- Detailed error messages
+- Logging integration
+- Recovery mechanisms
+
+## Testing
+
+### Test Structure
+
+1. **Unit Tests**
+   - Core functionality testing
+   - Settings management
+   - Time validation
+   - Error handling
+
+2. **Integration Tests**
+   - Notification scheduling
+   - Background tasks
+   - Settings persistence
+   - Event handling
+
+3. **Edge Cases**
+   - Timezone changes
+   - Battery optimization
+   - Network issues
+   - Resource cleanup
+
+### Running Tests
+
+```bash
+# Run all tests
+./gradlew test
+
+# Run specific test class
+./gradlew test --tests "com.timesafari.dailynotification.DailyNotificationPluginTest"
+
+# Run with coverage
+./gradlew test jacocoTestReport
+```
+
+## Security Considerations
+
+1. **Data Storage**
+   - Encrypted SharedPreferences for sensitive data
+   - Secure notification content handling
+   - Safe URL handling
+
+2. **Permissions**
+   - Runtime permission handling
+   - Permission validation
+   - Graceful degradation
+
+3. **Background Tasks**
+   - Battery optimization compliance
+   - Resource usage monitoring
+   - Task scheduling limits
+
+## Performance Optimization
+
+1. **Battery Usage**
+   - Efficient scheduling
+   - Background task optimization
+   - Wake lock management
+
+2. **Memory Management**
+   - Resource cleanup
+   - Memory leak prevention
+   - Cache management
+
+3. **Network Usage**
+   - Efficient data fetching
+   - Caching strategies
+   - Retry optimization
+
+## Best Practices
+
+1. **Code Organization**
+   - Clear package structure
+   - Consistent naming conventions
+   - Comprehensive documentation
+
+2. **Error Handling**
+   - Graceful degradation
+   - User-friendly messages
+   - Logging integration
+
+3. **Testing**
+   - Comprehensive test coverage
+   - Edge case handling
+   - Performance testing
+
+## Dependencies
+
+- AndroidX Core
+- AndroidX AppCompat
+- AndroidX WorkManager
+- AndroidX Room
+- AndroidX Lifecycle
+- AndroidX Security
+- JUnit
+- Mockito
+
+## Contributing
+
+1. Fork the repository
+2. Create a feature branch
+3. Commit your changes
+4. Push to the branch
+5. Create a Pull Request
+
+## License
+
+This project is licensed under the MIT License - see the LICENSE file for details.
+
+## Author
+
+Matthew Raymer
+
+# Daily Notification Plugin - Battery Optimization Guide
+
+## Battery Overview
+
+The Daily Notification Plugin implements sophisticated battery optimization features to ensure reliable notification delivery while minimizing battery impact. This guide covers the implementation details and best practices for battery optimization.
+
+## Battery Optimization Features
+
+### 1. Adaptive Scheduling
+
+- Adjusts notification timing based on battery level and power state
+- Reduces frequency during low battery conditions
+- Optimizes wake lock duration based on battery status
+- Implements smart rescheduling for missed notifications
+
+### 2. Power State Management
+
+- Monitors device power state (normal, power save, etc.)
+- Adapts notification behavior based on power mode
+- Implements Doze mode handling
+- Manages wake locks efficiently
+
+### 3. Battery Level Monitoring
+
+- Real-time battery level tracking
+- Charging state detection
+- Battery health monitoring
+- Adaptive thresholds based on battery status
+
+## API Methods
+
+### Battery Optimization
+
+```typescript
+interface BatteryOptimizationStatus {
+  isExempt: boolean;
+  requestTime: number;
+  checkTime: number;
+}
+
+// Request battery optimization exemption
+requestBatteryOptimizationExemption(): Promise<BatteryOptimizationStatus>;
+
+// Get current battery status
+getBatteryStatus(): Promise<{
+  level: number;
+  isCharging: boolean;
+  lastCheck: number;
+  isOptimizationExempt: boolean;
+  lastOptimizationCheck: number;
+  isInDozeMode: boolean;
+}>;
+
+// Get power state information
+getPowerState(): Promise<{
+  powerState: number;
+  adaptiveScheduling: boolean;
+  batteryLevel: number;
+  isCharging: boolean;
+  lastCheck: number;
+}>;
+
+// Configure adaptive scheduling
+setAdaptiveScheduling(enabled: boolean): Promise<void>;
+```
+
+## Implementation Details
+
+### Battery Optimization Exemption
+
+```java
+@PluginMethod
+public void requestBatteryOptimizationExemption(PluginCall call) {
+    // Implementation details...
+}
+```
+
+### Power State Monitoring
+
+```java
+private void updatePowerState() {
+    // Implementation details...
+}
+```
+
+### Adaptive Scheduling
+
+```java
+private void adjustSchedulingForBatteryLevel() {
+    // Implementation details...
+}
+```
+
+## Best Practices
+
+### 1. Battery Optimization Exemption
+- Request exemption only when necessary
+- Check exemption status before scheduling notifications
+- Implement fallback mechanisms when exemption is not granted
+
+### 2. Wake Lock Usage
+- Use minimal wake lock duration
+- Release wake locks promptly
+- Implement battery-aware wake lock duration
+
+### 3. Doze Mode Handling
+
+- Schedule maintenance windows during Doze mode
+- Use WorkManager for reliable background tasks
+- Implement backup alarms for critical notifications
+
+### 4. Battery Level Monitoring
+
+- Monitor battery level changes
+- Adjust notification frequency based on battery status
+- Implement battery-saving thresholds
+
+### 5. Power State Adaptation
+
+- Adapt to power save mode
+- Optimize resource usage during low power
+- Implement graceful degradation
+
+## Battery Error Handling
+
+### Battery Optimization during Error Handling
+
+```java
+try {
+    // Battery optimization code
+} catch (Exception e) {
+    logger.log("Error in battery optimization: " + e.getMessage(), 
+               DailyNotificationLogger.Level.ERROR);
+    // Handle error appropriately
+}
+```
+
+### Wake Lock
+
+```java
+try {
+    // Wake lock code
+} catch (Exception e) {
+    logger.log("Error managing wake lock: " + e.getMessage(), 
+               DailyNotificationLogger.Level.ERROR);
+    // Handle error appropriately
+}
+```
+
+### Doze Mode
+
+```java
+try {
+    // Doze mode handling code
+} catch (Exception e) {
+    logger.log("Error handling Doze mode: " + e.getMessage(), 
+               DailyNotificationLogger.Level.ERROR);
+    // Handle error appropriately
+}
+```
+
+## Performance Considerations
+
+### Battery Impact
+
+- Minimize wake lock usage
+- Optimize background task scheduling
+- Implement efficient battery monitoring
+
+### Resource Usage
+
+- Use WorkManager for background tasks
+- Implement efficient wake lock management
+- Optimize notification scheduling
+
+### Storage
+
+- Efficient battery stats storage
+- Optimized settings persistence
+- Minimal logging overhead
+
+## Security
+
+### Wake Lock Security
+
+- Use appropriate wake lock flags
+- Implement timeout mechanisms
+- Handle wake lock failures gracefully
+
+### Data Security
+
+- Secure storage of battery stats
+- Protected settings access
+- Safe logging practices
+
+## Testing
+
+### Battery Optimization Tests
+
+```java
+@Test
+void testBatteryOptimizationExemptionRequest() {
+    // Test implementation
+}
+```
+
+### Power State Tests
+
+```java
+@Test
+void testPowerStateMonitoring() {
+    // Test implementation
+}
+```
+
+### Performance Tests
+```java
+@Test
+void testBatteryImpact() {
+    // Test implementation
+}
+```
+
+## Contributing
+
+### Documentation
+- Keep documentation up to date
+- Document all battery optimization features
+- Include usage examples
+
+### Code
+- Follow battery optimization best practices
+- Implement comprehensive tests
+- Maintain backward compatibility
+
+## License
+MIT License - See LICENSE file for details 
\ No newline at end of file
diff --git a/android/app/src/test/java/com/timesafari/dailynotification/BatteryOptimizationSettingsTest.java b/android/app/src/test/java/com/timesafari/dailynotification/BatteryOptimizationSettingsTest.java
new file mode 100644
index 0000000..dce621b
--- /dev/null
+++ b/android/app/src/test/java/com/timesafari/dailynotification/BatteryOptimizationSettingsTest.java
@@ -0,0 +1,150 @@
+/**
+ * BatteryOptimizationSettingsTest.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Tests for battery optimization settings and power state management
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.BatteryManager;
+import android.os.Build;
+import android.os.PowerManager;
+import android.provider.Settings;
+
+import androidx.work.WorkManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.M})
+public class BatteryOptimizationSettingsTest {
+    
+    @Mock
+    private Context context;
+    
+    @Mock
+    private SharedPreferences settings;
+    
+    @Mock
+    private SharedPreferences.Editor editor;
+    
+    @Mock
+    private PowerManager powerManager;
+    
+    @Mock
+    private WorkManager workManager;
+    
+    private BatteryOptimizationSettings batterySettings;
+    
+    @Before
+    public void setUp() {
+        MockitoAnnotations.openMocks(this);
+        
+        when(context.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
+        when(settings.edit()).thenReturn(editor);
+        when(editor.putBoolean(anyString(), anyBoolean())).thenReturn(editor);
+        when(editor.putInt(anyString(), anyInt())).thenReturn(editor);
+        when(editor.putLong(anyString(), anyLong())).thenReturn(editor);
+        when(editor.apply()).thenReturn(true);
+        
+        batterySettings = new BatteryOptimizationSettings(context, settings);
+    }
+    
+    @Test
+    public void testRequestBatteryOptimizationExemption() {
+        // Test when already exempt
+        when(settings.getBoolean(anyString(), anyBoolean())).thenReturn(true);
+        assertTrue(batterySettings.requestBatteryOptimizationExemption());
+        
+        // Test when not exempt
+        when(settings.getBoolean(anyString(), anyBoolean())).thenReturn(false);
+        when(context.getPackageName()).thenReturn("com.test.app");
+        
+        Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
+        intent.setData(android.net.Uri.parse("package:com.test.app"));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        
+        batterySettings.requestBatteryOptimizationExemption();
+        
+        verify(context).startActivity(eq(intent));
+        verify(editor).putLong(eq("last_optimization_request"), anyLong());
+    }
+    
+    @Test
+    public void testUpdatePowerState() {
+        when(powerManager.getPowerState()).thenReturn(PowerManager.POWER_STATE_SAVE);
+        
+        batterySettings.updatePowerState();
+        
+        verify(editor).putInt(eq("power_state"), eq(PowerManager.POWER_STATE_SAVE));
+    }
+    
+    @Test
+    public void testUpdateBatteryStatus() {
+        Intent batteryStatus = new Intent(Intent.ACTION_BATTERY_CHANGED);
+        batteryStatus.putExtra(BatteryManager.EXTRA_LEVEL, 80);
+        batteryStatus.putExtra(BatteryManager.EXTRA_SCALE, 100);
+        batteryStatus.putExtra(BatteryManager.EXTRA_STATUS, BatteryManager.BATTERY_HEALTH_CHARGING);
+        
+        when(context.registerReceiver(any(), any())).thenReturn(batteryStatus);
+        
+        batterySettings.updateBatteryStatus();
+        
+        assertEquals(80, batterySettings.getBatteryLevel());
+        assertTrue(batterySettings.isCharging());
+        verify(editor).putInt(eq("last_battery_level"), eq(80));
+        verify(editor).putBoolean(eq("last_charging_state"), eq(true));
+    }
+    
+    @Test
+    public void testAdjustSchedulingForPowerState() {
+        // Test power save mode
+        when(powerManager.getPowerState()).thenReturn(PowerManager.POWER_STATE_SAVE);
+        batterySettings.updatePowerState();
+        assertTrue(batterySettings.shouldCheckBattery());
+        
+        // Test normal mode
+        when(powerManager.getPowerState()).thenReturn(PowerManager.POWER_STATE_NORMAL);
+        batterySettings.updatePowerState();
+        assertTrue(batterySettings.shouldCheckBattery());
+        
+        // Test optimized mode
+        when(powerManager.getPowerState()).thenReturn(PowerManager.POWER_STATE_OPTIMIZED);
+        batterySettings.updatePowerState();
+        assertTrue(batterySettings.shouldCheckBattery());
+    }
+    
+    @Test
+    public void testGetPowerStateString() {
+        assertEquals("POWER_SAVE", batterySettings.getPowerStateString(PowerManager.POWER_STATE_SAVE));
+        assertEquals("NORMAL", batterySettings.getPowerStateString(PowerManager.POWER_STATE_NORMAL));
+        assertEquals("OPTIMIZED", batterySettings.getPowerStateString(PowerManager.POWER_STATE_OPTIMIZED));
+        assertEquals("UNKNOWN", batterySettings.getPowerStateString(999));
+    }
+    
+    @Test
+    public void testShouldCheckBattery() {
+        // Test when check is needed
+        assertTrue(batterySettings.shouldCheckBattery());
+        
+        // Test when check is not needed
+        when(settings.getLong(anyString(), anyLong())).thenReturn(System.currentTimeMillis());
+        assertFalse(batterySettings.shouldCheckBattery());
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/test/java/com/timesafari/dailynotification/DailyNotificationLoggerTest.java b/android/app/src/test/java/com/timesafari/dailynotification/DailyNotificationLoggerTest.java
new file mode 100644
index 0000000..a94c4a5
--- /dev/null
+++ b/android/app/src/test/java/com/timesafari/dailynotification/DailyNotificationLoggerTest.java
@@ -0,0 +1,134 @@
+/**
+ * DailyNotificationLoggerTest.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Tests for logging functionality
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import static org.junit.Assert.*;
+
+@RunWith(RobolectricTestRunner.class)
+public class DailyNotificationLoggerTest {
+    
+    private DailyNotificationLogger logger;
+    
+    @Before
+    public void setUp() {
+        logger = new DailyNotificationLogger();
+    }
+    
+    @Test
+    public void testLogWithInfoLevel() {
+        // Test info level logging
+        logger.log("Test info message", DailyNotificationLogger.Level.INFO);
+        
+        // Verify log level
+        assertEquals(DailyNotificationLogger.Level.INFO, logger.getLastLogLevel());
+        
+        // Verify message
+        assertTrue(logger.getLastLogMessage().contains("Test info message"));
+    }
+    
+    @Test
+    public void testLogWithWarningLevel() {
+        // Test warning level logging
+        logger.log("Test warning message", DailyNotificationLogger.Level.WARNING);
+        
+        // Verify log level
+        assertEquals(DailyNotificationLogger.Level.WARNING, logger.getLastLogLevel());
+        
+        // Verify message
+        assertTrue(logger.getLastLogMessage().contains("Test warning message"));
+    }
+    
+    @Test
+    public void testLogWithErrorLevel() {
+        // Test error level logging
+        logger.log("Test error message", DailyNotificationLogger.Level.ERROR);
+        
+        // Verify log level
+        assertEquals(DailyNotificationLogger.Level.ERROR, logger.getLastLogLevel());
+        
+        // Verify message
+        assertTrue(logger.getLastLogMessage().contains("Test error message"));
+    }
+    
+    @Test
+    public void testLogWithDebugLevel() {
+        // Test debug level logging
+        logger.log("Test debug message", DailyNotificationLogger.Level.DEBUG);
+        
+        // Verify log level
+        assertEquals(DailyNotificationLogger.Level.DEBUG, logger.getLastLogLevel());
+        
+        // Verify message
+        assertTrue(logger.getLastLogMessage().contains("Test debug message"));
+    }
+    
+    @Test
+    public void testLogWithException() {
+        // Create test exception
+        Exception testException = new RuntimeException("Test exception");
+        
+        // Test logging with exception
+        logger.log("Test error with exception", DailyNotificationLogger.Level.ERROR, testException);
+        
+        // Verify log level
+        assertEquals(DailyNotificationLogger.Level.ERROR, logger.getLastLogLevel());
+        
+        // Verify message contains exception details
+        assertTrue(logger.getLastLogMessage().contains("Test error with exception"));
+        assertTrue(logger.getLastLogMessage().contains("Test exception"));
+    }
+    
+    @Test
+    public void testLogWithNullMessage() {
+        // Test logging with null message
+        logger.log(null, DailyNotificationLogger.Level.INFO);
+        
+        // Verify log level
+        assertEquals(DailyNotificationLogger.Level.INFO, logger.getLastLogLevel());
+        
+        // Verify message is empty
+        assertTrue(logger.getLastLogMessage().isEmpty());
+    }
+    
+    @Test
+    public void testLogWithNullLevel() {
+        // Test logging with null level
+        logger.log("Test message", null);
+        
+        // Verify default level is INFO
+        assertEquals(DailyNotificationLogger.Level.INFO, logger.getLastLogLevel());
+        
+        // Verify message
+        assertTrue(logger.getLastLogMessage().contains("Test message"));
+    }
+    
+    @Test
+    public void testLogWithTimestamp() {
+        // Test logging with timestamp
+        logger.log("Test message with timestamp", DailyNotificationLogger.Level.INFO);
+        
+        // Verify message contains timestamp
+        assertTrue(logger.getLastLogMessage().matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}.*"));
+    }
+    
+    @Test
+    public void testLogWithTag() {
+        // Test logging with tag
+        logger.log("Test message with tag", DailyNotificationLogger.Level.INFO, "TestTag");
+        
+        // Verify message contains tag
+        assertTrue(logger.getLastLogMessage().contains("[TestTag]"));
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/test/java/com/timesafari/dailynotification/DailyNotificationPluginTest.java b/android/app/src/test/java/com/timesafari/dailynotification/DailyNotificationPluginTest.java
new file mode 100644
index 0000000..2f78b85
--- /dev/null
+++ b/android/app/src/test/java/com/timesafari/dailynotification/DailyNotificationPluginTest.java
@@ -0,0 +1,194 @@
+/**
+ * DailyNotificationPluginTest.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Tests for the main plugin functionality
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import android.app.AlarmManager;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.os.PowerManager;
+
+import com.getcapacitor.JSObject;
+import com.getcapacitor.PluginCall;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.M})
+public class DailyNotificationPluginTest {
+    
+    @Mock
+    private Context context;
+    
+    @Mock
+    private SharedPreferences settings;
+    
+    @Mock
+    private SharedPreferences.Editor editor;
+    
+    @Mock
+    private NotificationManager notificationManager;
+    
+    @Mock
+    private AlarmManager alarmManager;
+    
+    @Mock
+    private PowerManager powerManager;
+    
+    @Mock
+    private PluginCall pluginCall;
+    
+    private DailyNotificationPlugin plugin;
+    
+    @Before
+    public void setUp() {
+        MockitoAnnotations.openMocks(this);
+        
+        when(context.getSystemService(Context.NOTIFICATION_SERVICE)).thenReturn(notificationManager);
+        when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(alarmManager);
+        when(context.getSystemService(Context.POWER_SERVICE)).thenReturn(powerManager);
+        when(settings.edit()).thenReturn(editor);
+        when(editor.putBoolean(anyString(), anyBoolean())).thenReturn(editor);
+        when(editor.putString(anyString(), anyString())).thenReturn(editor);
+        when(editor.putLong(anyString(), anyLong())).thenReturn(editor);
+        when(editor.apply()).thenReturn(true);
+        
+        plugin = new DailyNotificationPlugin();
+        plugin.load();
+    }
+    
+    @Test
+    public void testScheduleDailyNotification() {
+        // Setup test data
+        when(pluginCall.getString("url")).thenReturn("https://example.com");
+        when(pluginCall.getString("time")).thenReturn("09:00");
+        when(pluginCall.getString("title")).thenReturn("Test Notification");
+        when(pluginCall.getString("body")).thenReturn("Test Body");
+        when(pluginCall.getBoolean("sound", true)).thenReturn(true);
+        when(pluginCall.getString("priority", "default")).thenReturn("default");
+        
+        // Execute
+        plugin.scheduleDailyNotification(pluginCall);
+        
+        // Verify
+        verify(alarmManager).setExactAndAllowWhileIdle(
+            eq(AlarmManager.RTC_WAKEUP),
+            anyLong(),
+            any()
+        );
+        verify(editor).putString(eq("scheduled_time"), eq("09:00"));
+        verify(editor).putString(eq("notification_url"), eq("https://example.com"));
+    }
+    
+    @Test
+    public void testCancelAllNotifications() {
+        // Execute
+        plugin.cancelAllNotifications(pluginCall);
+        
+        // Verify
+        verify(alarmManager).cancel(any());
+        verify(notificationManager).cancelAll();
+    }
+    
+    @Test
+    public void testGetNotificationStatus() {
+        // Setup
+        when(notificationManager.areNotificationsEnabled()).thenReturn(true);
+        
+        // Execute
+        plugin.getNotificationStatus(pluginCall);
+        
+        // Verify
+        verify(pluginCall).resolve(any(JSObject.class));
+    }
+    
+    @Test
+    public void testUpdateSettings() {
+        // Setup
+        when(pluginCall.hasOption("sound")).thenReturn(true);
+        when(pluginCall.getBoolean("sound")).thenReturn(false);
+        when(pluginCall.hasOption("priority")).thenReturn(true);
+        when(pluginCall.getString("priority")).thenReturn("high");
+        
+        // Execute
+        plugin.updateSettings(pluginCall);
+        
+        // Verify
+        verify(editor).putBoolean("sound", false);
+        verify(editor).putString("priority", "high");
+    }
+    
+    @Test
+    public void testRequestBatteryOptimizationExemption() {
+        // Execute
+        plugin.requestBatteryOptimizationExemption(pluginCall);
+        
+        // Verify
+        verify(context).startActivity(any(Intent.class));
+    }
+    
+    @Test
+    public void testGetBatteryStatus() {
+        // Execute
+        plugin.getBatteryStatus(pluginCall);
+        
+        // Verify
+        verify(pluginCall).resolve(any(JSObject.class));
+    }
+    
+    @Test
+    public void testSetAdaptiveScheduling() {
+        // Setup
+        when(pluginCall.getBoolean("enabled", true)).thenReturn(true);
+        
+        // Execute
+        plugin.setAdaptiveScheduling(pluginCall);
+        
+        // Verify
+        verify(editor).putBoolean(eq("adaptive_scheduling"), eq(true));
+    }
+    
+    @Test
+    public void testGetPowerState() {
+        // Execute
+        plugin.getPowerState(pluginCall);
+        
+        // Verify
+        verify(pluginCall).resolve(any(JSObject.class));
+    }
+    
+    @Test
+    public void testHandleDozeMode() {
+        // Setup
+        when(powerManager.isDeviceIdleMode()).thenReturn(true);
+        
+        // Execute
+        plugin.handleDozeMode();
+        
+        // Verify
+        verify(alarmManager).setAndAllowWhileIdle(
+            eq(AlarmManager.RTC_WAKEUP),
+            anyLong(),
+            any()
+        );
+    }
+} 
\ No newline at end of file
diff --git a/android/app/src/test/java/com/timesafari/dailynotification/DailyNotificationReceiverTest.java b/android/app/src/test/java/com/timesafari/dailynotification/DailyNotificationReceiverTest.java
new file mode 100644
index 0000000..88a272e
--- /dev/null
+++ b/android/app/src/test/java/com/timesafari/dailynotification/DailyNotificationReceiverTest.java
@@ -0,0 +1,162 @@
+/**
+ * DailyNotificationReceiverTest.java
+ * Daily Notification Plugin for Capacitor
+ * 
+ * Tests for notification receiver functionality
+ * 
+ * @author Matthew Raymer
+ */
+
+package com.timesafari.dailynotification;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+
+import androidx.core.app.NotificationCompat;
+import androidx.core.app.NotificationManagerCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(sdk = {Build.VERSION_CODES.M})
+public class DailyNotificationReceiverTest {
+    
+    @Mock
+    private Context context;
+    
+    @Mock
+    private NotificationManager notificationManager;
+    
+    @Mock
+    private NotificationManagerCompat notificationManagerCompat;
+    
+    private DailyNotificationReceiver receiver;
+    
+    @Before
+    public void setUp() {
+        MockitoAnnotations.openMocks(this);
+        
+        when(context.getSystemService(Context.NOTIFICATION_SERVICE))
+            .thenReturn(notificationManager);
+        when(NotificationManagerCompat.from(context))
+            .thenReturn(notificationManagerCompat);
+            
+        receiver = new DailyNotificationReceiver();
+    }
+    
+    @Test
+    public void testOnReceive() {
+        // Setup test data
+        Intent intent = new Intent();
+        intent.putExtra("url", "https://example.com");
+        intent.putExtra("title", "Test Notification");
+        intent.putExtra("body", "Test Body");
+        intent.putExtra("sound", true);
+        intent.putExtra("priority", "high");
+        
+        // Execute
+        receiver.onReceive(context, intent);
+        
+        // Verify
+        verify(notificationManagerCompat).notify(
+            eq("https://example.com".hashCode()),
+            any(Notification.class)
+        );
+    }
+    
+    @Test
+    public void testOnReceiveWithMissingParameters() {
+        // Setup test data
+        Intent intent = new Intent();
+        
+        // Execute
+        receiver.onReceive(context, intent);
+        
+        // Verify
+        verify(notificationManagerCompat, never()).notify(anyInt(), any(Notification.class));
+    }
+    
+    @Test
+    public void testShowNotification() {
+        // Setup test data
+        String title = "Test Notification";
+        String body = "Test Body";
+        String url = "https://example.com";
+        boolean sound = true;
+        String priority = "high";
+        
+        // Execute
+        receiver.showNotification(context, title, body, url, sound, priority);
+        
+        // Verify
+        verify(notificationManagerCompat).notify(
+            eq(url.hashCode()),
+            any(Notification.class)
+        );
+    }
+    
+    @Test
+    public void testAddCustomActions() {
+        // Setup test data
+        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "test_channel");
+        String url = "https://example.com";
+        
+        // Execute
+        receiver.addCustomActions(builder, context, url);
+        
+        // Verify
+        verify(context, times(3)).getClass();
+    }
+    
+    @Test
+    public void testGetNotificationPriority() {
+        // Test high priority
+        assertEquals(
+            NotificationCompat.PRIORITY_HIGH,
+            receiver.getNotificationPriority("high")
+        );
+        
+        // Test low priority
+        assertEquals(
+            NotificationCompat.PRIORITY_LOW,
+            receiver.getNotificationPriority("low")
+        );
+        
+        // Test default priority
+        assertEquals(
+            NotificationCompat.PRIORITY_DEFAULT,
+            receiver.getNotificationPriority("default")
+        );
+        
+        // Test unknown priority
+        assertEquals(
+            NotificationCompat.PRIORITY_DEFAULT,
+            receiver.getNotificationPriority("unknown")
+        );
+    }
+    
+    @Test
+    public void testCreateNotificationChannel() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+            // Execute
+            receiver.createNotificationChannel(context);
+            
+            // Verify
+            verify(notificationManager).createNotificationChannel(any(NotificationChannel.class));
+        }
+    }
+} 
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index b831f78..1d3e084 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -35,15 +35,20 @@ android {
     buildTypes {
         release {
             minifyEnabled false
-            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
         }
     }
     lintOptions {
         abortOnError false
     }
     compileOptions {
-        sourceCompatibility JavaVersion.VERSION_17
-        targetCompatibility JavaVersion.VERSION_17
+        sourceCompatibility JavaVersion.VERSION_1_8
+        targetCompatibility JavaVersion.VERSION_1_8
+    }
+    testOptions {
+        unitTests {
+            includeAndroidResources = true
+        }
     }
 }
 
@@ -67,11 +72,38 @@ repositories {
 }
 
 dependencies {
-    implementation fileTree(include: ['*.jar'], dir: 'libs')
+    // AndroidX Core
+    implementation 'androidx.core:core:1.7.0'
+    implementation 'androidx.core:core-ktx:1.7.0'
+    
+    // WorkManager for background tasks
+    implementation 'androidx.work:work-runtime:2.7.1'
+    
+    // Capacitor dependencies
     implementation project(':capacitor-android')
-    implementation project(':capacitor-cordova-android-plugins')
-    implementation 'androidx.work:work-runtime:2.8.1'
+    implementation project(':capacitor-core')
+    
+    // Testing dependencies
     testImplementation 'junit:junit:4.13.2'
+    testImplementation 'org.mockito:mockito-core:4.5.1'
+    testImplementation 'org.robolectric:robolectric:4.8'
+    testImplementation 'androidx.test:core:1.4.0'
+    testImplementation 'androidx.test:runner:1.4.0'
+    testImplementation 'androidx.test.ext:junit:1.1.3'
+    
+    // AndroidX Test
     androidTestImplementation 'androidx.test.ext:junit:1.1.5'
     androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
+    
+    // AndroidX AppCompat
+    implementation 'androidx.appcompat:appcompat:1.6.1'
+    
+    // AndroidX Core App
+    implementation 'androidx.core:core-app:1.0.0'
+    
+    // AndroidX Core AppCompat
+    implementation 'androidx.core:core-appcompat:1.0.0'
+    
+    // AndroidX Core AppCompat Resources
+    implementation 'androidx.core:core-appcompat-resources:1.0.0'
 }
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..3823b52
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,6 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ *
+ * This is a general purpose Gradle build.
+ * Learn more about Gradle by exploring our Samples at https://docs.gradle.org/8.13/samples
+ */
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..5154008
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,7 @@
+# This file was generated by the Gradle 'init' task.
+# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
+
+org.gradle.configuration-cache=true
+org.gradle.parallel=true
+org.gradle.caching=true
+
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 0000000..9a968dc
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,10 @@
+# This file was generated by the Gradle 'init' task.
+# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
+
+[versions]
+commons-math3 = "3.6.1"
+guava = "33.3.1-jre"
+
+[libraries]
+commons-math3 = { module = "org.apache.commons:commons-math3", version.ref = "commons-math3" }
+guava = { module = "com.google.guava:guava", version.ref = "guava" }
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..9bbc975
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..37f853b
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..faf9300
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,251 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+##############################################################################
+#
+#   Gradle start up script for POSIX generated by Gradle.
+#
+#   Important for running:
+#
+#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+#       noncompliant, but you have some other compliant shell such as ksh or
+#       bash, then to run this script, type that shell name before the whole
+#       command line, like:
+#
+#           ksh Gradle
+#
+#       Busybox and similar reduced shells will NOT work, because this script
+#       requires all of these POSIX shell features:
+#         * functions;
+#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+#         * compound commands having a testable exit status, especially «case»;
+#         * various built-in commands including «command», «set», and «ulimit».
+#
+#   Important for patching:
+#
+#   (2) This script targets any POSIX shell, so it avoids extensions provided
+#       by Bash, Ksh, etc; in particular arrays are avoided.
+#
+#       The "traditional" practice of packing multiple parameters into a
+#       space-separated string is a well documented source of bugs and security
+#       problems, so this is (mostly) avoided, by progressively accumulating
+#       options in "$@", and eventually passing that to Java.
+#
+#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+#       see the in-line comments for details.
+#
+#       There are tweaks for specific operating systems such as AIX, CygWin,
+#       Darwin, MinGW, and NonStop.
+#
+#   (3) This script is generated from the Groovy template
+#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+#       within the Gradle project.
+#
+#       You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+    APP_HOME=${app_path%"${app_path##*/}"}  # leaves a trailing /; empty if no leading path
+    [ -h "$app_path" ]
+do
+    ls=$( ls -ld "$app_path" )
+    link=${ls#*' -> '}
+    case $link in             #(
+      /*)   app_path=$link ;; #(
+      *)    app_path=$APP_HOME$link ;;
+    esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+    echo "$*"
+} >&2
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in                #(
+  CYGWIN* )         cygwin=true  ;; #(
+  Darwin* )         darwin=true  ;; #(
+  MSYS* | MINGW* )  msys=true    ;; #(
+  NONSTOP* )        nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD=$JAVA_HOME/jre/sh/java
+    else
+        JAVACMD=$JAVA_HOME/bin/java
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD=java
+    if ! command -v java >/dev/null 2>&1
+    then
+        die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+    case $MAX_FD in #(
+      max*)
+        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        MAX_FD=$( ulimit -H -n ) ||
+            warn "Could not query maximum file descriptor limit"
+    esac
+    case $MAX_FD in  #(
+      '' | soft) :;; #(
+      *)
+        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+        # shellcheck disable=SC2039,SC3045
+        ulimit -n "$MAX_FD" ||
+            warn "Could not set maximum file descriptor limit to $MAX_FD"
+    esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+#   * args from the command line
+#   * the main class name
+#   * -classpath
+#   * -D...appname settings
+#   * --module-path (only if needed)
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+    APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+    CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+    JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    for arg do
+        if
+            case $arg in                                #(
+              -*)   false ;;                            # don't mess with options #(
+              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath
+                    [ -e "$t" ] ;;                      #(
+              *)    false ;;
+            esac
+        then
+            arg=$( cygpath --path --ignore --mixed "$arg" )
+        fi
+        # Roll the args list around exactly as many times as the number of
+        # args, so each arg winds up back in the position where it started, but
+        # possibly modified.
+        #
+        # NB: a `for` loop captures its iteration list before it begins, so
+        # changing the positional parameters here affects neither the number of
+        # iterations, nor the values presented in `arg`.
+        shift                   # remove old arg
+        set -- "$@" "$arg"      # push replacement arg
+    done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+#     and any embedded shellness will be escaped.
+#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+#     treated as '${Hostname}' itself on the command line.
+
+set -- \
+        "-Dorg.gradle.appname=$APP_BASE_NAME" \
+        -classpath "$CLASSPATH" \
+        org.gradle.wrapper.GradleWrapperMain \
+        "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+    die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+#   readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+#   set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+        printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+        xargs -n1 |
+        sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+        tr '\n' ' '
+    )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..9d21a21
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,94 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem      https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+@rem SPDX-License-Identifier: Apache-2.0
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lib/build.gradle.kts b/lib/build.gradle.kts
new file mode 100644
index 0000000..d323030
--- /dev/null
+++ b/lib/build.gradle.kts
@@ -0,0 +1,42 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ *
+ * This generated file contains a sample Java library project to get you started.
+ * For more details on building Java & JVM projects, please refer to https://docs.gradle.org/8.13/userguide/building_java_projects.html in the Gradle documentation.
+ * This project uses @Incubating APIs which are subject to change.
+ */
+
+plugins {
+    // Apply the java-library plugin for API and implementation separation.
+    `java-library`
+}
+
+repositories {
+    // Use Maven Central for resolving dependencies.
+    mavenCentral()
+}
+
+dependencies {
+    // This dependency is exported to consumers, that is to say found on their compile classpath.
+    api(libs.commons.math3)
+
+    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
+    implementation(libs.guava)
+}
+
+testing {
+    suites {
+        // Configure the built-in test suite
+        val test by getting(JvmTestSuite::class) {
+            // Use JUnit Jupiter test framework
+            useJUnitJupiter("5.11.3")
+        }
+    }
+}
+
+// Apply a specific Java toolchain to ease working on different environments.
+java {
+    toolchain {
+        languageVersion = JavaLanguageVersion.of(21)
+    }
+}
diff --git a/lib/src/main/java/org/example/Library.java b/lib/src/main/java/org/example/Library.java
new file mode 100644
index 0000000..b98461b
--- /dev/null
+++ b/lib/src/main/java/org/example/Library.java
@@ -0,0 +1,10 @@
+/*
+ * This source file was generated by the Gradle 'init' task
+ */
+package org.example;
+
+public class Library {
+    public boolean someLibraryMethod() {
+        return true;
+    }
+}
diff --git a/lib/src/test/java/org/example/LibraryTest.java b/lib/src/test/java/org/example/LibraryTest.java
new file mode 100644
index 0000000..ef34950
--- /dev/null
+++ b/lib/src/test/java/org/example/LibraryTest.java
@@ -0,0 +1,14 @@
+/*
+ * This source file was generated by the Gradle 'init' task
+ */
+package org.example;
+
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+
+class LibraryTest {
+    @Test void someLibraryMethodReturnsTrue() {
+        Library classUnderTest = new Library();
+        assertTrue(classUnderTest.someLibraryMethod(), "someLibraryMethod should return 'true'");
+    }
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..7c49a62
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,15 @@
+/*
+ * This file was generated by the Gradle 'init' task.
+ *
+ * The settings file is used to specify which projects to include in your build.
+ * For more detailed information on multi-project builds, please refer to https://docs.gradle.org/8.13/userguide/multi_project_builds.html in the Gradle documentation.
+ * This project uses @Incubating APIs which are subject to change.
+ */
+
+plugins {
+    // Apply the foojay-resolver plugin to allow automatic download of JDKs
+    id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0"
+}
+
+rootProject.name = "daily-notification-plugin"
+include("lib")