# Android Notification Implementation Comparison

**Test App (Working)** vs **TimeSafari (Not Working)**

This document identifies the critical differences between the test app where notifications work correctly and the TimeSafari app where notifications don't work at all. Use this as a checklist to fix TimeSafari.

---

## Critical Issues (Must Fix)

### 1. Missing Custom Application Class

**This is likely the primary cause of failure.**

**Test App (Working):**
```xml
<!-- AndroidManifest.xml -->
<application
    android:name=".TestApplication"
    ...>
```

```java
// TestApplication.java
public class TestApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        
        Context context = getApplicationContext();
        NativeNotificationContentFetcher testFetcher = 
            new org.timesafari.dailynotification.test.TestNativeFetcher(context);
        DailyNotificationPlugin.setNativeFetcher(testFetcher);
    }
}
```

**TimeSafari (Broken):**
```xml
<!-- AndroidManifest.xml - NO android:name attribute -->
<application
    android:allowBackup="true"
    ...>
```
- No custom Application class exists
- No native fetcher is registered
- Plugin cannot fetch notification content

**Fix Required:**
1. Create `TimeSafariApplication.java` in `android/app/src/main/java/app/timesafari/`
2. Implement `NativeNotificationContentFetcher` specific to TimeSafari
3. Add `android:name=".TimeSafariApplication"` to AndroidManifest.xml

---

### 2. Missing Capacitor Plugin Configuration

**Test App (Working):**
```typescript
// capacitor.config.ts
plugins: {
  DailyNotification: {
    debugMode: true,
    enableNotifications: true,
    timesafariConfig: {
      activeDid: "did:ethr:0x...",
      endpoints: {
        projectsLastUpdated: "http://..."
      },
      starredProjectsConfig: {
        enabled: true,
        starredPlanHandleIds: [...],
        fetchInterval: '0 8 * * *'
      },
      credentialConfig: {
        jwtSecret: '...',
        tokenExpirationMinutes: 1
      }
    },
    networkConfig: {
      timeout: 30000,
      retryAttempts: 3,
      retryDelay: 1000
    },
    contentFetch: {
      enabled: true,
      schedule: '0 00 * * *',
      fetchLeadTimeMinutes: 5
    }
  }
}
```

**TimeSafari (Broken):**
```typescript
// capacitor.config.ts - NO DailyNotification configuration at all
plugins: {
  App: { ... },
  SplashScreen: { ... },
  CapSQLite: { ... }
  // DailyNotification is MISSING
}
```

**Fix Required:**
Add `DailyNotification` configuration to `capacitor.config.ts` with appropriate values for TimeSafari.

---

### 3. Missing Permissions in AndroidManifest.xml

**Test App has these permissions that TimeSafari is missing:**

```xml
<!-- Add to TimeSafari's AndroidManifest.xml -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
```

**Current TimeSafari permissions (incomplete):**
- ✅ `INTERNET`
- ✅ `POST_NOTIFICATIONS`
- ✅ `SCHEDULE_EXACT_ALARM`
- ✅ `RECEIVE_BOOT_COMPLETED`
- ✅ `WAKE_LOCK`
- ❌ `ACCESS_NETWORK_STATE` - **MISSING**
- ❌ `FOREGROUND_SERVICE` - **MISSING**
- ❌ `SYSTEM_ALERT_WINDOW` - **MISSING**
- ❌ `REQUEST_IGNORE_BATTERY_OPTIMIZATIONS` - **MISSING**

---

### 4. Missing Gradle Dependencies

**Test App (Working):**
```gradle
// android/app/build.gradle
dependencies {
    // Capacitor annotation processor for automatic plugin discovery
    annotationProcessor project(':capacitor-android')
    
    // Required dependencies for the plugin
    implementation 'androidx.work:work-runtime:2.9.0'
    implementation 'androidx.lifecycle:lifecycle-service:2.7.0'
    implementation 'com.google.code.gson:gson:2.10.1'
}
```

**TimeSafari (Broken):**
```gradle
dependencies {
    // Missing: annotationProcessor project(':capacitor-android')
    implementation "androidx.work:work-runtime-ktx:2.9.0"  // Using Kotlin version
    // Missing: androidx.lifecycle:lifecycle-service
    // Missing: com.google.code.gson:gson
}
```

**Fix Required:**
Add to TimeSafari's `android/app/build.gradle`:
```gradle
annotationProcessor project(':capacitor-android')
implementation 'androidx.lifecycle:lifecycle-service:2.7.0'
implementation 'com.google.code.gson:gson:2.10.1'
```

---

## Secondary Issues (Should Fix)

### 5. DailyNotificationReceiver Export Status

**Test App (Working):**
```xml
<receiver
    android:name="org.timesafari.dailynotification.DailyNotificationReceiver"
    android:enabled="true"
    android:exported="false">  <!-- Note: false -->
```

**TimeSafari (Broken):**
```xml
<receiver
    android:name="org.timesafari.dailynotification.DailyNotificationReceiver"
    android:enabled="true"
    android:exported="true">  <!-- Note: true - potential security issue -->
```

The test app uses `exported="false"` because the plugin creates PendingIntents with explicit component targeting. Using `exported="true"` is unnecessary and a potential security concern.

---

### 6. Missing Network Security Config

**Test App (Working):**
```xml
<application
    android:networkSecurityConfig="@xml/network_security_config"
    ...>
```

**TimeSafari (Broken):**
```xml
<application>
    <!-- No networkSecurityConfig -->
```

This may affect HTTP (non-HTTPS) requests during development.

---

### 7. Missing Java Compile Options

**Test App (Working):**
```gradle
android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
}
```

**TimeSafari (Broken):**
No explicit compile options set.

---

## Complete Fix Checklist

### Step 1: Create Custom Application Class

Create file: `android/app/src/main/java/app/timesafari/TimeSafariApplication.java`

```java
package app.timesafari;

import android.app.Application;
import android.content.Context;
import android.util.Log;
import org.timesafari.dailynotification.DailyNotificationPlugin;
import org.timesafari.dailynotification.NativeNotificationContentFetcher;

public class TimeSafariApplication extends Application {
    
    private static final String TAG = "TimeSafariApplication";
    
    @Override
    public void onCreate() {
        super.onCreate();
        
        Log.i(TAG, "Initializing TimeSafari notifications");
        
        // Register native fetcher with application context
        Context context = getApplicationContext();
        NativeNotificationContentFetcher fetcher = 
            new TimeSafariNativeFetcher(context);
        DailyNotificationPlugin.setNativeFetcher(fetcher);
        
        Log.i(TAG, "Native fetcher registered");
    }
}
```

### Step 2: Create Native Fetcher Implementation

Create file: `android/app/src/main/java/app/timesafari/TimeSafariNativeFetcher.java`

```java
package app.timesafari;

import android.content.Context;
import org.timesafari.dailynotification.NativeNotificationContentFetcher;
import org.timesafari.dailynotification.NotificationContent;

public class TimeSafariNativeFetcher implements NativeNotificationContentFetcher {
    
    private final Context context;
    
    public TimeSafariNativeFetcher(Context context) {
        this.context = context;
    }
    
    @Override
    public NotificationContent fetchContent(String scheduleId) {
        // TODO: Implement actual content fetching for TimeSafari
        // This should query the TimeSafari API for notification content
        return new NotificationContent(
            "timesafari_" + System.currentTimeMillis(),
            "TimeSafari Update",
            "Check your starred projects for updates!",
            System.currentTimeMillis(),
            null,
            System.currentTimeMillis()
        );
    }
}
```

### Step 3: Update AndroidManifest.xml

```xml
<?xml version="1.0" encoding="utf-8" ?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application
        android:name=".TimeSafariApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:networkSecurityConfig="@xml/network_security_config"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        
        <!-- ... existing content ... -->
        
        <!-- Fix: Change exported to false -->
        <receiver
            android:name="org.timesafari.dailynotification.DailyNotificationReceiver"
            android:enabled="true"
            android:exported="false">
            <intent-filter>
                <action android:name="org.timesafari.daily.NOTIFICATION" />
            </intent-filter>
        </receiver>
        
        <!-- ... rest of receivers ... -->
        
    </application>

    <!-- Existing permissions -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    
    <!-- ADD these missing permissions -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
</manifest>
```

### Step 4: Update build.gradle

Add to `android/app/build.gradle`:

```gradle
android {
    // ... existing config ...
    
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }
}

dependencies {
    // ... existing dependencies ...
    
    // ADD these for notification plugin
    annotationProcessor project(':capacitor-android')
    implementation 'androidx.lifecycle:lifecycle-service:2.7.0'
    implementation 'com.google.code.gson:gson:2.10.1'
}
```

### Step 5: Update capacitor.config.ts

Add DailyNotification configuration:

```typescript
plugins: {
    // ... existing plugins ...
    
    DailyNotification: {
      debugMode: true,
      enableNotifications: true,
      timesafariConfig: {
        activeDid: '', // Will be set dynamically from user's DID
        endpoints: {
          projectsLastUpdated: 'https://api.endorser.ch/api/v2/report/plansLastUpdatedBetween'
        },
        starredProjectsConfig: {
          enabled: true,
          starredPlanHandleIds: [],
          fetchInterval: '0 8 * * *'
        }
      },
      networkConfig: {
        timeout: 30000,
        retryAttempts: 3,
        retryDelay: 1000
      },
      contentFetch: {
        enabled: true,
        schedule: '0 8 * * *',
        fetchLeadTimeMinutes: 5
      }
    }
}
```

### Step 6: Rebuild

```bash
npx cap sync android
cd android && ./gradlew clean
cd .. && npx cap build android
```

---

## Verification

After implementing fixes, verify:

1. **Check logs for Application initialization:**
   ```bash
   adb logcat | grep -E "TimeSafariApplication|Native fetcher"
   ```

2. **Check alarm scheduling:**
   ```bash
   adb shell dumpsys alarm | grep -i timesafari
   ```

3. **Test receiver manually:**
   ```bash
   adb shell am broadcast -a org.timesafari.daily.NOTIFICATION \
     --es id "test_notification" \
     -n app.timesafari.app/org.timesafari.dailynotification.DailyNotificationReceiver
   ```

4. **Check notification permissions:**
   ```bash
   adb shell dumpsys package app.timesafari.app | grep -A 5 "granted=true"
   ```

---

## Summary of Critical Differences

| Component | Test App (Working) | TimeSafari (Broken) |
|-----------|-------------------|---------------------|
| Custom Application class | ✅ TestApplication.java | ❌ None |
| Native fetcher registration | ✅ In Application.onCreate() | ❌ Not registered |
| DailyNotification config | ✅ Full config in capacitor.config.ts | ❌ Not configured |
| ACCESS_NETWORK_STATE | ✅ Present | ❌ Missing |
| FOREGROUND_SERVICE | ✅ Present | ❌ Missing |
| REQUEST_IGNORE_BATTERY_OPTIMIZATIONS | ✅ Present | ❌ Missing |
| Gson dependency | ✅ Present | ❌ Missing |
| lifecycle-service dependency | ✅ Present | ❌ Missing |
| Capacitor annotation processor | ✅ Present | ❌ Missing |

**The most critical missing piece is the custom Application class with native fetcher registration.** Without this, the plugin has no way to fetch notification content when the alarm fires.
