v0.1.0-T (vc=7): bug fixes + Opus audit pass #2 + home redesign
User-visible: - BUG: 'clicking a second item went back to the first video' — VideoDetailViewModel guard was short-circuiting on Activity-scoped ViewModel reuse. Now tracks loadedUrl and only skips when the requested URL matches. - BUG: PiP / window mode now auto-enters on Home gesture (Android 12+ via setAutoEnterEnabled). Manual PiP button reports failure cause via Toast. - HOME REDESIGN: replaced 3-tab bottom nav with hamburger ModalNavigationDrawer. Default view = sub feed. Drawer items = Subscriptions / History / Search / Settings. Top-left hamburger like normal Android apps. Audit pass #2 (Opus max-effort) — CRIT + HIGH fixes shipped: - CRIT-1: PlaybackService now calls startForeground() inside onStartCommand with a media-playback notification + channel. Pre-fix could throw ForegroundServiceDidNotStartInTimeException on Android 12+ and crash-kill. - CRIT-2: AndroidManifest service exported=false. Previously any installed app could craft an Intent and drive playback from attacker URLs. - HIGH-1: 🎧 background handoff stops the activity player before starting the service so we don't dual-host two ExoPlayers + MediaSessions. - HIGH-2: onStartCommand returns START_NOT_STICKY and tears down on null intent; no more crash-restart-crash loop after OS kills. - HIGH-3: stop service on STATE_ENDED / STATE_IDLE via Player.Listener. onTaskRemoved checks playbackState properly so we don't hold WAKE_LOCK forever after a video ends in background. - HIGH-4: Downloader validates scheme=https + googlevideo/youtube host before handing the URL to DownloadManager. - HIGH-5: filename sanitization extended to ASCII control chars, DEL, Unicode bidi-override block, leading-dot, trailing whitespace. - HIGH-6: SubscriptionFeedViewModel cancels prior in-flight refresh, caps parallelism at 8 via Semaphore, applies 15s per-channel timeout. - HIGH-7: sub feed error banner now shows above cached items when refresh fails (previously hidden, looked indistinguishable from success). - HIGH-8: PlayerViewModel falls back to lowest-available stream when no stream is under the max-resolution ceiling (was: silent black screen). - HIGH-9: network_security_config explicit cleartextTrafficPermitted='false' on the RYD domain-config block (doesn't inherit from base-config). - MED-1: PlaybackService.onDestroy nulls field before releasing session to close a race with onGetSession during teardown. - MED-6: Downloader catches enqueue exceptions, returns -1L, caller toasts 'download refused (bad URL)' instead of crashing. Deferred (audit said 'can wait'): MED-2..5, MED-7..11, HIGH-10 UX consistency.
This commit is contained in:
parent
081f238355
commit
9550b207ab
11 changed files with 510 additions and 267 deletions
|
|
@ -47,10 +47,14 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Phase M-2: MediaSessionService for background audio + notification + lock-screen controls. -->
|
||||
<!-- Phase M-2 / S: MediaSessionService for background audio + notification + lock-screen
|
||||
controls. Marked NOT exported (audit CRIT-2): any installed app can otherwise
|
||||
craft an Intent with the MediaSessionService action and drive playback from
|
||||
attacker-controlled URLs. The intent-filter stays so the Media3 session router
|
||||
can find the service within our own process. -->
|
||||
<service
|
||||
android:name=".feature.player.PlaybackService"
|
||||
android:exported="true"
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="mediaPlayback">
|
||||
<intent-filter>
|
||||
<action android:name="androidx.media3.session.MediaSessionService" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue