export {}; /** * The takeover must reach the screen from the background. * * Measured on an Android 15 emulator: the alarm rang with the app backgrounded, * but `AlarmActivity` was refused by the platform — * `Background activity launch blocked! … BAL_BLOCK` — because an activity launched * from the alarm's own PendingIntent is subject to the Android 14+ background * launch rules. The siren was audible and nothing was on screen. * * The platform's sanctioned path is a notification **full-screen intent**, which * SystemUI launches. These assertions pin that structure, because it cannot be * exercised in a Jest run (no Android runtime): the firing notification must * carry the FSI, the alarm category and the takeover's own intent, and silencing * the alarm must retract it. */ declare const __dirname: string; const fs = require('fs') as { readFileSync(p: string, enc: string): string }; const path = require('path') as { join(...parts: string[]): string }; const NATIVE = path.join( __dirname, '..', 'android', 'app', 'src', 'main', 'java', 'com', 'dcntrlized', 'alarm', ); const player = fs.readFileSync(path.join(NATIVE, 'AlarmPlayer.kt'), 'utf8'); const service = fs.readFileSync(path.join(NATIVE, 'AlarmForegroundService.kt'), 'utf8'); describe('background takeover launch', () => { it('posts a full-screen-intent notification for a trigger', () => { expect(player).toContain('fun showFiring('); expect(player).toContain('setFullScreenIntent(open, true)'); expect(player).toContain('Notification.CATEGORY_ALARM'); expect(player).toContain('AlarmActivity.intent(context, alertId, message)'); }); it('raises it from the service that received the frame', () => { const at = service.indexOf('"trigger" ->'); expect(at).toBeGreaterThan(-1); const branch = service.slice(at, at + 700); expect(branch).toContain('AlarmNotifier.showFiring('); expect(branch.indexOf('showFiring')).toBeLessThan(branch.indexOf('AlarmPlayer.play')); }); it('retracts it when the alarm is silenced — but not from AlarmPlayer.stop', () => { // play() calls stop() first, so cancelling there retracted the full-screen // intent on every single trigger (measured: NotificationService "Cannot find // enqueued record for key 4713" 120 ms after the trigger). const stop = player.slice(player.indexOf('fun stop(context: Context)')); expect(stop.slice(0, 1200)).not.toContain('cancelFiring'); expect(service).toContain('AlarmNotifier.cancelFiring(this)'); // A disarm and an explicit stop both retract it. expect(service.split('AlarmNotifier.cancelFiring(this)').length - 1).toBeGreaterThanOrEqual(2); }); it('closes its own window when the user leaves — a route pop is not enough', () => { // Measured on the emulator: after acknowledging, the app returned to its // previous screen but the AlarmActivity window stayed on top for good // (show-when-locked, keep-screen-on, excludeFromRecents) — the reported // "no way back to the main menu". const activity = fs.readFileSync(path.join(NATIVE, 'AlarmActivity.kt'), 'utf8'); const bridge = fs.readFileSync(path.join(NATIVE, 'AlarmModule.kt'), 'utf8'); const screen = fs.readFileSync( path.join(__dirname, '..', 'src', 'screens', 'LiveAlarmScreen.tsx'), 'utf8', ); expect(activity).toContain('fun currentActivity()'); expect(activity).toContain('current = null'); const finishAt = bridge.indexOf('fun finishTakeover('); expect(finishAt).toBeGreaterThan(-1); expect(bridge.slice(finishAt, finishAt + 400)).toContain('.finish()'); const leaveAt = screen.indexOf('const leave = useCallback('); expect(screen.slice(leaveAt, leaveAt + 600)).toContain('finishTakeover()'); }); it('tells the truth when the FSI grant is missing', () => { expect(player).toContain('canUseFullScreenIntent()'); expect(player).toContain('heads-up only'); }); });