Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android Auto #578

Merged
merged 48 commits into from
Jun 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
6a2238d
Move _includeItemTypes() to TabContentType
puff Jan 17, 2024
8da2b09
Basic Android Auto support
puff Jan 17, 2024
d168fb7
Try using downloaded parent before going online in Android Auto
puff Jan 17, 2024
f877624
Add shuffle to Android Auto
puff Jan 18, 2024
56d4f2a
Use correct shuffle status for Android Auto
puff Jan 18, 2024
05e5f72
Artists now start instant mix in Android Auto
puff Jan 20, 2024
efb14bd
synchronize internal queue and Android media queue
Chaphasilor Jan 21, 2024
0789c31
fix adding to next up when shuffle is active
Chaphasilor Jan 21, 2024
7a24508
Add sorting to Android Auto and make offline sort by name case-insens…
puff Jan 22, 2024
aad1edf
Remove unused parameter in Android Auto getBaseItems
puff Jan 22, 2024
99d01f2
Only sort downloaded items if not playing them in Android Auto
puff Jan 22, 2024
b3656c8
Use a ContentProvider to resolve artwork for Android Auto
puff Jan 23, 2024
ea10a21
Basic voice search for songs in Android Auto
puff Feb 4, 2024
4200036
Merge branch 'redesign' into pr/puff/578
Chaphasilor Feb 6, 2024
430ee62
enable showing search results for android auto voice search
Chaphasilor Feb 6, 2024
c85c07b
rename use parent instead of category
Chaphasilor Feb 6, 2024
121a87e
implement starting instant mixes from search results
Chaphasilor Feb 6, 2024
8d2d825
improved playBySearch using extras
Chaphasilor Feb 7, 2024
0c34cfc
Download images in MediaItemContentProvider
puff Feb 16, 2024
bcc22c0
replaced manual passing and parsing of media IDs with serializable Me…
Chaphasilor Feb 16, 2024
c0355e2
use item ID instead of parent ID
Chaphasilor Feb 16, 2024
72cc75a
Remove redundant TabContentType resolves in Android Auto code
puff Feb 17, 2024
b66d3ec
Merge branch 'redesign' into pr/puff/578
Chaphasilor Feb 17, 2024
32d213f
shuffle all for empty search query ("play some music")
Chaphasilor Feb 17, 2024
a03199f
increase timeout for http requests
Chaphasilor Feb 19, 2024
1febde3
Re-implement MediaItemContentProvider in Kotlin
puff Mar 8, 2024
4e70118
improve search using metadata where possible
Chaphasilor Mar 9, 2024
d8a11e2
prefer playlists for voice search
Chaphasilor Mar 9, 2024
294fa6f
Merge branch 'redesign' into pr/puff/578
Chaphasilor Mar 9, 2024
be80fb6
make voice search artist match case insensitive
Chaphasilor Mar 9, 2024
ea6ec93
Use correct item type id in Android Auto
puff Mar 10, 2024
09df0c1
only resolve songs from downloads in online mode, add artist playback…
Chaphasilor Mar 10, 2024
40e5bb5
also use grid layout in Android Auto if enabled
Chaphasilor Mar 10, 2024
c4baf85
improve offline mode for Android Auto
Chaphasilor Mar 10, 2024
d1aefd1
merge branch 'redesign'
Chaphasilor Mar 23, 2024
5797b16
disable artwork preloading in media session due to issues with custom…
Chaphasilor Mar 23, 2024
a2cb78b
Merge branch 'redesign' into pr/puff/578
Chaphasilor May 24, 2024
f37784d
added offline support for voice commands
Chaphasilor May 26, 2024
895fe77
explicitly handle request for recent ("For you") root
Chaphasilor May 26, 2024
289f3b2
fix syntax error
Chaphasilor May 26, 2024
adf2a81
improvements based on review
Chaphasilor May 27, 2024
6d12f78
fix errors, properly join file paths
Chaphasilor May 27, 2024
03470f9
fix issues with content provider custom artwork URIs
Chaphasilor May 27, 2024
ddc66e8
fix album name always being shown
Chaphasilor May 27, 2024
4274089
search multiple item types
Chaphasilor May 30, 2024
68d3b3d
added like button to media notification, added settings for customizi…
Chaphasilor May 30, 2024
1901816
Merge branch 'redesign' into pr/puff/578
Chaphasilor May 30, 2024
ae315fb
Merge branch 'redesign' into pr/puff/578
Chaphasilor Jun 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,7 @@ android {
flutter {
source '../..'
}

dependencies {
implementation 'androidx.appcompat:appcompat:1.3.1'
}
28 changes: 26 additions & 2 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,16 @@
<category android:name="android.intent.category.APP_MUSIC"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<service android:name="com.ryanheise.audioservice.AudioService" android:foregroundServiceType="mediaPlayback"
android:exported="true">
<provider
android:name=".MediaItemContentProvider"
android:authorities="com.unicornsonlsd.finamp"
android:exported="true" />
<service android:name="com.ryanheise.audioservice.AudioService" android:foregroundServiceType="mediaPlayback" android:exported="true">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService" />
</intent-filter>
Expand All @@ -43,6 +50,10 @@
</intent-filter>
</receiver>

<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc" />

<meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="true" />
Expand All @@ -51,4 +62,17 @@
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data android:name="flutterEmbedding" android:value="2" />
</application>

<uses-feature
android:name="android.hardware.type.automotive"
android:required="true" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.portrait"
android:required="false" />
<uses-feature
android:name="android.hardware.screen.landscape"
android:required="false" />
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ package com.unicornsonlsd.finamp
import io.flutter.embedding.android.FlutterActivity

class MainActivity: FlutterActivity() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package com.unicornsonlsd.finamp

import android.content.ContentProvider
import android.content.ContentValues
import android.database.Cursor
import android.net.Uri
import android.os.ParcelFileDescriptor
import android.util.LruCache
import java.io.File
import java.io.FileOutputStream
import java.net.URL

class MediaItemContentProvider : ContentProvider() {

private lateinit var memoryCache : LruCache<String, ByteArray>

override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? {
if (uri.fragment != null) {
// we store the original scheme://host in fragment since it should be unused
val origin = Uri.parse(uri.fragment)
val fixedUri = uri.buildUpon().fragment(null).scheme(origin.scheme).authority(origin.authority).toString()

// check if we already cached the image
val bytes = memoryCache.get(fixedUri)
if (bytes != null) {
return openPipeHelper(uri, "application/octet-stream", null, bytes) {output, _, _, _, b ->
FileOutputStream(output.fileDescriptor).write(b)
}
}

val response = URL(fixedUri).readBytes()
memoryCache.put(fixedUri, response)
return openPipeHelper(uri, "application/octet-stream", null, response) {output, _, _, _, b ->
FileOutputStream(output.fileDescriptor).write(b)
}
}

// this means it's a local image (downloaded or placeholder art)
return ParcelFileDescriptor.open(File(uri.path!!), ParcelFileDescriptor.MODE_READ_ONLY)
}

override fun onCreate(): Boolean {
// Get max available VM memory, exceeding this amount will throw an
// OutOfMemory exception. Stored in kilobytes as LruCache takes an
// int in its constructor.
val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()

// Use 1/8th of the available memory for this memory cache.
val cacheSize = maxMemory / 8
memoryCache = object : LruCache<String, ByteArray>(cacheSize) {

override fun sizeOf(key: String, value: ByteArray): Int {
// The cache size will be measured in kilobytes rather than
// number of items.
return value.size / 1024
}
}

return true
}

override fun query(uri: Uri, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor? {
return null
}

override fun getType(uri: Uri): String? {
return null
}

override fun insert(uri: Uri, values: ContentValues?): Uri? {
return null
}

override fun delete(uri: Uri, selection: String?, selectionArgs: Array<out String>?): Int {
return 0
}

override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int {
return 0
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions android/app/src/main/res/drawable/baseline_heart_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:strokeWidth="2"
android:strokeColor="@android:color/white"
android:pathData="M19.5 12.572l-7.5 7.428l-7.5 -7.428a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572"/>
</vector>
10 changes: 10 additions & 0 deletions android/app/src/main/res/drawable/baseline_heart_filled_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M6.979 3.074a6 6 0 0 1 4.988 1.425l.037 .033l.034 -.03a6 6 0 0 1 4.733 -1.44l.246 .036a6 6 0 0 1 3.364 10.008l-.18 .185l-.048 .041l-7.45 7.379a1 1 0 0 1 -1.313 .082l-.094 -.082l-7.493 -7.422a6 6 0 0 1 3.176 -10.215z"/>
</vector>
19 changes: 19 additions & 0 deletions android/app/src/main/res/drawable/baseline_shuffle_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path android:strokeWidth="2"
android:strokeColor="@android:color/white"
android:pathData="M21 17l-18 0" />
<path android:strokeWidth="2"
android:strokeColor="@android:color/white"
android:pathData="M18 4l3 3l-3 3" />
<path android:strokeWidth="2"
android:strokeColor="@android:color/white"
android:pathData="M18 20l3 -3l-3 -3" />
<path android:strokeWidth="2"
android:strokeColor="@android:color/white"
android:pathData="M21 7l-18 0" />
</vector>
22 changes: 22 additions & 0 deletions android/app/src/main/res/drawable/baseline_shuffle_on_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path android:strokeWidth="2"
android:strokeColor="@android:color/white"
android:pathData="M16 4h4v4" />
<path android:strokeWidth="2"
android:strokeColor="@android:color/white"
android:pathData="M15 9l5 -5" />
<path android:strokeWidth="2"
android:strokeColor="@android:color/white"
android:pathData="M4 20l5 -5" />
<path android:strokeWidth="2"
android:strokeColor="@android:color/white"
android:pathData="M16 20h4v-4" />
<path android:strokeWidth="2"
android:strokeColor="@android:color/white"
android:pathData="M4 4l16 16" />
</vector>
12 changes: 12 additions & 0 deletions android/app/src/main/res/drawable/baseline_stop_24.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:strokeWidth="2"
android:strokeColor="@android:color/white"
android:fillColor="@android:color/white"
android:pathData="M17 4h-10a3 3 0 0 0 -3 3v10a3 3 0 0 0 3 3h10a3 3 0 0 0 3 -3v-10a3 3 0 0 0 -3 -3z"/>
</vector>
3 changes: 3 additions & 0 deletions android/app/src/main/res/xml/automotive_app_desc.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<automotiveApp>
<uses name="media"/>
</automotiveApp>
Binary file added images/album_white.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 4 additions & 6 deletions lib/components/AlbumScreen/song_list_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -274,13 +274,13 @@ class _SongListTileState extends ConsumerState<SongListTile>
// TODO put in a real offline songs implementation
if (FinampSettingsHelper.finampSettings.isOffline) {
final settings = FinampSettingsHelper.finampSettings;
final downloadService = GetIt.instance<DownloadsService>();
final downloadsService = GetIt.instance<DownloadsService>();
final finampUserHelper = GetIt.instance<FinampUserHelper>();

// get all downloaded songs in order
List<DownloadStub> offlineItems;
// If we're on the songs tab, just get all of the downloaded items
offlineItems = await downloadService.getAllSongs(
offlineItems = await downloadsService.getAllSongs(
// nameFilter: widget.searchTerm,
viewFilter: finampUserHelper.currentUser?.currentView?.id,
nullableViewFilters:
Expand All @@ -306,10 +306,8 @@ class _SongListTileState extends ConsumerState<SongListTile>
(element) => element.id == widget.item.id)
: await widget.index,
source: QueueItemSource(
name: QueueItemSourceName(
type: QueueItemSourceNameType.preTranslated,
pretranslatedName:
AppLocalizations.of(context)!.placeholderSource),
name: const QueueItemSourceName(
type: QueueItemSourceNameType.mix),
type: QueueItemSourceType.allSongs,
id: widget.item.id,
),
Expand Down
2 changes: 1 addition & 1 deletion lib/components/DownloadsScreen/downloads_overview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class DownloadsOverview extends StatelessWidget {
stream: downloadsService.downloadCountsStream,
initialData: downloadsService.downloadCounts,
builder: (context, countSnapshot) {
// This is throttled to 10 per second in downloadService constructor.
// This is throttled to 10 per second in downloadsService constructor.
return StreamBuilder<Map<DownloadItemState, int>>(
stream: downloadsService.downloadStatusesStream,
initialData: downloadsService.downloadStatuses,
Expand Down
3 changes: 2 additions & 1 deletion lib/components/PlayerScreen/queue_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:finamp/services/feedback_helper.dart';
import 'package:finamp/services/finamp_settings_helper.dart';
import 'package:finamp/services/theme_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_sticky_header/flutter_sticky_header.dart';
Expand Down Expand Up @@ -803,7 +804,7 @@ class _CurrentTrackState extends State<CurrentTrack> {
width: (screenSize.width -
2 * horizontalPadding -
albumImageSize) *
(playbackPosition!.inMilliseconds /
((playbackPosition?.inMilliseconds ?? 0) /
(mediaState?.mediaItem
?.duration ??
const Duration(
Expand Down
114 changes: 114 additions & 0 deletions lib/gen/assets.gen.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.