import fs from 'node:fs'; import path from 'node:path'; const root = path.resolve(__dirname, '..'); const android = path.join(root, 'android', 'app', 'src', 'main'); function read(relativePath: string): string { return fs.readFileSync(path.join(android, relativePath), 'utf8'); } describe('Android foreground recording contract', () => { test('declares the microphone foreground service and required permissions', () => { const manifest = read('AndroidManifest.xml'); expect(manifest).toContain('android.permission.FOREGROUND_SERVICE_MICROPHONE'); expect(manifest).toContain('android.permission.WAKE_LOCK'); expect(manifest).toContain('android:name=".D3RORecordingService"'); expect(manifest).toContain('android:foregroundServiceType="microphone"'); expect(manifest).toContain('android:stopWithTask="false"'); }); test('checkpoints a WAV, handles audio focus and never restarts capture invisibly', () => { const service = read(path.join('java', 'com', 'd3ro', 'voice', 'D3RORecordingService.kt')); const journal = read(path.join('java', 'com', 'd3ro', 'voice', 'D3RORecordingJournal.kt')); expect(service).toContain('ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE'); expect(service).toContain('AUDIOFOCUS_LOSS_TRANSIENT'); expect(service).toContain('isClientSilenced'); expect(service).toContain('START_NOT_STICKY'); expect(service).toContain('MIN_CONTINUE_FREE_BYTES'); expect(journal).toContain('fun recoverAbandoned'); expect(journal).toContain('writeWavHeader'); expect(journal).toContain('process-restarted'); }); test('FileProvider exposes only staged cache files with read-only URI grants', () => { const manifest = read('AndroidManifest.xml'); const paths = read(path.join('res', 'xml', 'd3ro_file_paths.xml')); const module = read(path.join('java', 'com', 'd3ro', 'voice', 'D3ROFileShareModule.kt')); const portableFile = fs.readFileSync( path.join(root, 'src', 'features', 'data-portability', 'portable-file.ts'), 'utf8', ); expect(manifest).toContain('android:exported="false"'); expect(paths).toContain('path="shared_exports/"'); expect(paths).not.toContain('path="portable_exports/"'); expect(paths).not.toContain('path="."'); expect(module).toContain('PORTABLE_EXPORT_DIRECTORY = "portable_exports"'); expect(module).toContain('candidate.parentFile == sourceDirectory'); expect(portableFile).toContain("PORTABLE_EXPORT_DIRECTORY = 'portable_exports'"); expect(portableFile).toContain('await FileSystem.mkdir(directory)'); expect(module).toContain('Intent.FLAG_GRANT_READ_URI_PERMISSION'); expect(module).not.toContain('FLAG_GRANT_WRITE_URI_PERMISSION'); expect(module).toContain('revokeUriPermission'); }); });