The InfiniteStories app prevents the phone from sleeping during critical operations:
- Audio Playback: When a bedtime story is playing
- Illustration Generation: During AI-powered illustration creation (long-running operation)
This ensures parents don't have to worry about the phone's screen timing out during story playback or illustration generation.
-
Import UIKit: Added UIKit import to access
UIApplication.shared.isIdleTimerDisabled -
Idle Timer Control Methods:
disableIdleTimer(): SetsUIApplication.shared.isIdleTimerDisabled = trueenableIdleTimer(): SetsUIApplication.shared.isIdleTimerDisabled = false- Both methods use
DispatchQueue.main.asyncto ensure UI updates happen on the main thread
-
Playback State Management:
- When audio starts playing (MP3 or TTS): Idle timer is disabled
- When audio pauses: Idle timer is re-enabled
- When audio stops: Idle timer is re-enabled
- When audio resumes: Idle timer is disabled again
- When audio finishes naturally: Idle timer is re-enabled
-
App Lifecycle Handling:
appWillResignActive: Checks if audio is playing, re-enables idle timer if notappDidBecomeActive: Checks if audio is playing, disables idle timer if yes- Audio interruption handling: Manages idle timer during phone calls or other interruptions
-
Delegate Methods Updated:
AVAudioPlayerDelegate: Handles idle timer when audio finishes or encounters errorsAVSpeechSynthesizerDelegate: Manages idle timer for text-to-speech playback
The app now uses a centralized IdleTimerManager singleton service with reference counting to handle multiple simultaneous requests:
- Reference Counting: Multiple components can request idle timer disable without conflict
- Thread Safety: Uses concurrent queue with barriers for thread-safe operations
- Context Tracking: Each request includes a context string for debugging
- Automatic Cleanup: Idle timer is only re-enabled when all requests are released
-
StoryViewModel Integration:
- Disables idle timer when
generateIllustrationsForStory()starts - Re-enables when generation completes or fails
- Handles cancellation properly with cleanup
- Disables idle timer when
-
Long-Running Operations:
- Illustration generation can take 30-60 seconds per image
- Multiple illustrations generated sequentially
- Prevents screen sleep during entire generation process
-
Manual Retry Support:
- Idle timer disabled during manual illustration retry
- Properly managed for both single and batch retries
-
Cleanup in deinit: The AudioService deinit ensures idle timer is re-enabled when the service is deallocated
-
View Lifecycle: AudioPlayerView.onDisappear explicitly re-enables idle timer as a safety measure
-
Error Handling: Idle timer is re-enabled on any playback errors or generation failures
-
Reference Counting: IdleTimerManager prevents premature re-enabling when multiple operations are active
- Story is actively playing (audio or TTS)
- Audio is resumed after being paused
- Illustrations are being generated (30-60 seconds per image)
- Manual illustration retry is in progress
- Batch retry of failed illustrations is running
- No audio is playing
- Audio is paused
- Audio is stopped
- Audio finishes playing
- User leaves the audio player screen
- App encounters an error during playback
- Illustration generation completes (success or failure)
- Illustration generation is cancelled
- All active operations complete
-
Power Management: The implementation follows iOS best practices by only disabling the idle timer during active operations
-
Background Audio: The app uses
.playbackaudio session category, allowing:- Audio to continue when the screen is manually locked
- Audio to continue when the app goes to background
- Proper handling of audio interruptions (phone calls, etc.)
-
Thread Safety:
- All idle timer updates are dispatched to the main queue
- IdleTimerManager uses concurrent queue with barriers for thread-safe reference counting
-
Illustration Viewing:
- Idle timer is NOT disabled during passive illustration viewing/carousel navigation
- Only disabled during active generation to prevent interruption of API calls
- This conserves battery during passive content consumption
-
Manual Testing:
- Start playing a story and wait to confirm the screen doesn't dim/lock
- Pause the story and verify the screen can dim/lock normally
- Test interruptions (receive a phone call during playback)
- Test app backgrounding and foregrounding scenarios
- Start illustration generation and verify screen stays awake
- Cancel illustration generation and verify idle timer re-enables
-
Edge Cases to Test:
- Switching between MP3 and TTS playback
- Using playback speed controls
- Seeking through audio
- Multiple pause/resume cycles
- Simultaneous audio playback and illustration generation
- Illustration retry during audio playback
- App termination during illustration generation
- User Convenience: Parents don't need to adjust their phone's auto-lock settings
- Battery Optimization: Idle timer is only disabled when necessary
- Consistent Experience: Works for both MP3 files and text-to-speech
- Robust Error Handling: Fails safely by re-enabling idle timer on any error
- Long Operation Support: Prevents interruption of illustration generation
- Smart Power Management: Distinguishes between active operations and passive viewing
-
Generation Phase:
- Idle timer disabled only during active API calls
- Minimal battery impact as screen can still dim (brightness reduction)
- Network operations continue uninterrupted
-
Viewing Phase:
- Idle timer follows normal system behavior
- Screen can sleep during passive carousel viewing
- Audio playback controls idle timer independently
-
Memory Management:
- IdleTimerManager uses minimal memory with reference counting
- No retention of illustration data or views
- Proper cleanup on view dismissal or app termination