Files
Deepwave/app/src/main/AndroidManifest.xml
T
christopherandClaude Sonnet 5 53d4a73309 Phase 6.5: Android Auto (phone-projection)
Adds a real browse tree to DeepwavePlaybackService, replacing the
Phase 4 stub callback: root -> Playlists/Artists/Albums/Downloaded ->
drill-down -> tracks. Built entirely on Phase 3/5/6's existing
repositories (LibraryRepository, PlaylistRepository,
DownloadRepository) - no new Subsonic calls. A logged-out root shows
a single "log in on your phone first" placeholder instead of the
four categories, since Auto shares the same process/session as the
phone app rather than having its own login flow.

Also wires voice/typed search (onSearch/onGetSearchResult) through
the existing search3-backed LibraryRepository.search(), and
onAddMediaItems to rebuild a streamable URI when the car hands a
browsed item back for playback - a MediaItem's URI doesn't survive
the trip across into Android Auto's process, only its metadata does,
so this reconstructs it from the media id rather than re-fetching
anything.

No androidx.car.app dependency: that library targets navigation/POI
apps, not media - Auto's media category is driven entirely by
MediaLibraryService + media3-session + the automotive_app_desc.xml
manifest declaration added here.

Verified: full app rebuild, Hilt's DI graph resolves with BrowseTree
injected into DeepwavePlaybackService, all unit tests pass, and
in-app playback on the phone itself still works correctly through
the new session callback (confirmed via dumpsys media_session and
logcat, no crashes) - the regression risk of swapping the stub
callback for a real one. Every onGetLibraryRoot/onGetChildren/
onAddMediaItems/onSearch/onGetSearchResult override was verified by
the Kotlin compiler to correctly match Media3 1.11.1's actual
MediaLibrarySession.Callback signatures.

Not verified: the actual browse tree over a live Android Auto
connection. This device has no car or head unit to connect to, and
the Desktop Head Unit tool isn't installed on this machine (Google
no longer ships it through the standard SDK Manager - it's a
separate download). Recommend testing with the actual DHU tool or a
real car/head unit before relying on this in the car.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 19:02:48 -04:00

81 lines
3.9 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<application
android:name=".DeepwaveApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Deepwave">
<!-- Declares phone-projection Android Auto media support; combined with
DeepwavePlaybackService's MediaSessionService intent-filter below, this is the whole
manifest side of Auto discovery - no separate androidx.car.app dependency needed,
that library targets navigation/POI apps, not media. -->
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc" />
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Deepwave"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".media.DeepwavePlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService" />
</intent-filter>
</service>
<!-- WorkManager's own internal foreground-work service, declared with no type in the
library's manifest - on API 29+, startForeground() requires the type passed at
runtime (dataSync, in DownloadWorker) to be a subset of what's manifest-declared
for the actual service class handling it, which is this one, not DownloadWorker
itself. Without this override, every download crashes the app on setForeground(). -->
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync"
tools:node="merge" />
<!-- WorkManager is initialized manually in DeepwaveApplication.onCreate(), after Hilt's
field injection has run, so HiltWorkerFactory is actually set before anything can
call WorkManager.getInstance(). Without removing this, the default auto-init runs
first (via this same androidx.startup provider) with WorkManager's built-in
reflection-based factory, which can't construct @HiltWorker/@AssistedInject workers. -->
<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">
<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />
</provider>
</application>
</manifest>