diff --git a/app/build.gradle b/app/build.gradle index 104a8f9a..5ac7feed 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -13,7 +13,7 @@ android { vectorDrawables.useSupportLibrary = true applicationId "code.name.monkey.retromusic" - versionCode 352 + versionCode 353 versionName '3.3.100' multiDexEnabled true diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4f39ddd1..5dfe9e91 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,18 @@ + + + + + + + + + + + + - - - - - - - - + @@ -252,30 +247,30 @@ + android:resource="@xml/automotive_app_desc"/> + android:resource="@drawable/ic_notification"/> + + + + + + + + - - - - - - - - - - - - - - diff --git a/app/src/main/assets/retro-changelog.html b/app/src/main/assets/retro-changelog.html index cf09b953..3cc479cf 100644 --- a/app/src/main/assets/retro-changelog.html +++ b/app/src/main/assets/retro-changelog.html @@ -1 +1 @@ -

v3.3.000

v3.2.240

v3.2.220

v3.2.203

v3.2.135

v3.2.125

v3.2.120

v3.2.105

v3.2.100

v3.2.000

v3.1.900

v3.1.850

v3.1.800

v3.1.700

v3.1.400

v3.1.300

v3.1.240

v3.1.200

v3.0.570

If you see entire app white or dark or black select same theme in settings to fix

FAQ's

*If you face any UI related issues you clear app data and cache, if its not working try to uninstall and install again.

\ No newline at end of file +

v.3.3.100

v3.3.000

v3.2.240

v3.2.220

v3.2.203

v3.2.135

v3.2.125

v3.2.120

v3.2.105

v3.2.100

v3.2.000

v3.1.900

v3.1.850

v3.1.800

v3.1.700

v3.1.400

v3.1.300

v3.1.240

v3.1.200

v3.0.570

If you see entire app white or dark or black select same theme in settings to fix

FAQ's

*If you face any UI related issues you clear app data and cache, if its not working try to uninstall and install again.

\ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/auto/AutoMediaIDHelper.java b/app/src/main/java/code/name/monkey/retromusic/auto/AutoMediaIDHelper.java index 35858c76..563dd743 100644 --- a/app/src/main/java/code/name/monkey/retromusic/auto/AutoMediaIDHelper.java +++ b/app/src/main/java/code/name/monkey/retromusic/auto/AutoMediaIDHelper.java @@ -30,6 +30,7 @@ public class AutoMediaIDHelper { public static final String MEDIA_ID_MUSICS_BY_PLAYLIST = "__BY_PLAYLIST__"; public static final String MEDIA_ID_MUSICS_BY_ALBUM = "__BY_ALBUM__"; public static final String MEDIA_ID_MUSICS_BY_ARTIST = "__BY_ARTIST__"; + public static final String MEDIA_ID_MUSICS_BY_GENRE = "__BY_GENRE__"; public static final String MEDIA_ID_MUSICS_BY_SHUFFLE = "__BY_SHUFFLE__"; public static final String MEDIA_ID_MUSICS_BY_QUEUE = "__BY_QUEUE__"; diff --git a/app/src/main/java/code/name/monkey/retromusic/auto/AutoMusicProvider.java b/app/src/main/java/code/name/monkey/retromusic/auto/AutoMusicProvider.java index 77cae609..ea13395c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/auto/AutoMusicProvider.java +++ b/app/src/main/java/code/name/monkey/retromusic/auto/AutoMusicProvider.java @@ -32,19 +32,19 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentSkipListMap; -import code.name.monkey.appthemehelper.ThemeStore; import code.name.monkey.retromusic.R; import code.name.monkey.retromusic.loaders.AlbumLoader; import code.name.monkey.retromusic.loaders.ArtistLoader; +import code.name.monkey.retromusic.loaders.GenreLoader; import code.name.monkey.retromusic.loaders.PlaylistLoader; import code.name.monkey.retromusic.loaders.TopAndRecentlyPlayedTracksLoader; import code.name.monkey.retromusic.model.Album; import code.name.monkey.retromusic.model.Artist; +import code.name.monkey.retromusic.model.Genre; import code.name.monkey.retromusic.model.Playlist; import code.name.monkey.retromusic.model.Song; import code.name.monkey.retromusic.providers.MusicPlaybackQueueStore; import code.name.monkey.retromusic.service.MusicService; -import code.name.monkey.retromusic.util.ImageUtil; /** * Created by Beesham Sarendranauth (Beesham) @@ -57,7 +57,10 @@ public class AutoMusicProvider { private static final int PATH_SEGMENT_ID = 0; private static final int PATH_SEGMENT_TITLE = 1; private static final int PATH_SEGMENT_ARTIST = 2; + private static final int PATH_SEGMENT_GENRE = 4; + private static final int PATH_SEGMENT_ALBUM_ID = 5; + private WeakReference mMusicService; // Categorized caches for music data private ConcurrentMap mMusicListByHistory; @@ -65,6 +68,7 @@ public class AutoMusicProvider { private ConcurrentMap mMusicListByPlaylist; private ConcurrentMap mMusicListByAlbum; private ConcurrentMap mMusicListByArtist; + private ConcurrentMap mMusicListByGenre; private Uri defaultAlbumArtUri; @@ -79,12 +83,17 @@ public class AutoMusicProvider { mMusicListByPlaylist = new ConcurrentSkipListMap<>(); mMusicListByAlbum = new ConcurrentSkipListMap<>(); mMusicListByArtist = new ConcurrentSkipListMap<>(); + mMusicListByGenre = new ConcurrentSkipListMap<>(); defaultAlbumArtUri = Uri.parse("android.resource://" + mContext.getPackageName() + "/drawable/" + mContext.getResources().getResourceEntryName(R.drawable.default_album_art)); } + public void setMusicService(MusicService service) { + mMusicService = new WeakReference<>(service); + } + public Iterable getHistory() { if (mCurrentState != State.INITIALIZED) { return Collections.emptyList(); @@ -120,6 +129,13 @@ public class AutoMusicProvider { return mMusicListByArtist.values(); } + public Iterable getGenres() { + if (mCurrentState != State.INITIALIZED) { + return Collections.emptyList(); + } + return mMusicListByGenre.values(); + } + public Iterable getQueue() { if (mCurrentState != State.INITIALIZED) { return Collections.emptyList(); @@ -128,8 +144,9 @@ public class AutoMusicProvider { // Re-built every time since the queue updates often ConcurrentMap queueList = new ConcurrentSkipListMap<>(); - if (mContext != null) { - final List songs = MusicPlaybackQueueStore.getInstance(mContext).getSavedOriginalPlayingQueue(); + final MusicService service = mMusicService.get(); + if (service != null) { + final List songs = MusicPlaybackQueueStore.getInstance(service).getSavedOriginalPlayingQueue(); for (int i = 0; i < songs.size(); i++) { final Song s = songs.get(i); Uri.Builder topTracksData = Uri.parse(BASE_URI).buildUpon(); @@ -260,6 +277,21 @@ public class AutoMusicProvider { mMusicListByArtist = newMusicListByArtist; } + private synchronized void buildListsByGenre() { + ConcurrentMap newMusicListByGenre = new ConcurrentSkipListMap<>(); + + final List genres = GenreLoader.INSTANCE.getAllGenres(mContext); + for (int i = 0; i < genres.size(); i++) { + final Genre p = genres.get(i); + Uri.Builder playlistData = Uri.parse(BASE_URI).buildUpon(); + playlistData.appendPath(String.valueOf(p.getId())) + .appendPath(p.getName()); + newMusicListByGenre.putIfAbsent(i, playlistData.build()); + } + + mMusicListByGenre = newMusicListByGenre; + } + private synchronized void retrieveMedia() { try { if (mCurrentState == State.NON_INITIALIZED) { @@ -270,6 +302,7 @@ public class AutoMusicProvider { buildListsByPlaylist(); buildListsByAlbum(); buildListsByArtist(); + buildListsByGenre(); mCurrentState = State.INITIALIZED; } } finally { @@ -290,13 +323,31 @@ public class AutoMusicProvider { switch (mediaId) { case AutoMediaIDHelper.MEDIA_ID_ROOT: - mediaItems.add(createBrowsableMediaItem(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_HISTORY, resources.getString(R.string.history_label), R.drawable.ic_access_time_white_24dp)); - mediaItems.add(createBrowsableMediaItem(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_TOP_TRACKS, resources.getString(R.string.top_tracks_label), R.drawable.ic_trending_up_white_24dp)); - mediaItems.add(createBrowsableMediaItem(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_PLAYLIST, resources.getString(R.string.playlists_label), R.drawable.ic_queue_music_white_24dp)); - mediaItems.add(createBrowsableMediaItem(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM, resources.getString(R.string.albums_label), R.drawable.ic_album_white_24dp)); - mediaItems.add(createBrowsableMediaItem(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST, resources.getString(R.string.artists_label), R.drawable.ic_artist_white_24dp)); - mediaItems.add(createPlayableMediaItem(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_SHUFFLE, resources.getString(R.string.action_shuffle_all), R.drawable.ic_shuffle_white_24dp, null)); - mediaItems.add(createBrowsableMediaItem(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_QUEUE, resources.getString(R.string.queue_label), R.drawable.ic_playlist_play_white_24dp)); + //mediaItems.add(createBrowsableMediaItem(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_HISTORY, resources.getString(R.string.history_label), R.drawable.ic_access_time_white_24dp)); + //mediaItems.add(createBrowsableMediaItem(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_TOP_TRACKS, resources.getString(R.string.top_tracks_label), R.drawable.ic_trending_up_white_24dp)); + //mediaItems.add(createBrowsableMediaItem(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_PLAYLIST, resources.getString(R.string.playlists_label), R.drawable.ic_queue_music_white_24dp)); + mediaItems.add( + createBrowsableMediaItem( + AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_ALBUM, + resources.getString(R.string.albums_label), + R.drawable.ic_album_white_24dp)); + mediaItems.add( + createBrowsableMediaItem( + AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_ARTIST, + resources.getString(R.string.artists_label), + R.drawable.ic_artist_white_24dp)); + mediaItems.add( + createBrowsableMediaItem( + AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_GENRE, + resources.getString(R.string.genres_label), + R.drawable.ic_guitar_acoustic_white_24dp)); + mediaItems.add( + createPlayableMediaItem( + AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_SHUFFLE, + resources.getString(R.string.action_shuffle_all), + R.drawable.ic_shuffle_white_24dp, + "")); + //mediaItems.add(createBrowsableMediaItem(AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_QUEUE, resources.getString(R.string.queue_label), R.drawable.ic_playlist_play_white_24dp)); break; case AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_HISTORY: @@ -328,6 +379,11 @@ public class AutoMusicProvider { mediaItems.add(createPlayableMediaItem(mediaId, uri, uri.getPathSegments().get(PATH_SEGMENT_ARTIST), null)); } break; + case AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_GENRE: + for (final Uri uri : getGenres()) { + mediaItems.add(createPlayableMediaItem(mediaId, uri, uri.getPathSegments().get(PATH_SEGMENT_TITLE), null)); + } + break; case AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_QUEUE: // TODO: auto scroll to current track, indicate that it's playing @@ -343,21 +399,25 @@ public class AutoMusicProvider { private MediaBrowserCompat.MediaItem createBrowsableMediaItem(String mediaId, String title, int iconDrawableId) { MediaDescriptionCompat.Builder builder = new MediaDescriptionCompat.Builder(); builder.setMediaId(mediaId) - .setTitle(title) - .setIconBitmap(ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(mContext, iconDrawableId, ThemeStore.Companion.textColorSecondary(mContext)))); + .setTitle(title); return new MediaBrowserCompat.MediaItem(builder.build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE); } - private MediaBrowserCompat.MediaItem createPlayableMediaItem(String mediaId, Uri musicSelection, - String title, @Nullable String subtitle) { + private MediaBrowserCompat.MediaItem createPlayableMediaItem(String mediaId, + Uri musicSelection, + String title, + @Nullable String subtitle) { return createPlayableMediaItem(mediaId, musicSelection, title, subtitle, null, null); } - private MediaBrowserCompat.MediaItem createPlayableMediaItem(String mediaId, Uri musicSelection, - String title, @Nullable String subtitle, - @Nullable Bitmap albumArt, @Nullable Resources resources) { + private MediaBrowserCompat.MediaItem createPlayableMediaItem(String mediaId, + Uri musicSelection, + String title, + @Nullable String subtitle, + @Nullable Bitmap albumArt, + @Nullable Resources resources) { MediaDescriptionCompat.Builder builder = new MediaDescriptionCompat.Builder(); builder.setMediaId(AutoMediaIDHelper.createMediaID(musicSelection.getPathSegments().get(PATH_SEGMENT_ID), mediaId)) .setTitle(title); @@ -378,12 +438,13 @@ public class AutoMusicProvider { MediaBrowserCompat.MediaItem.FLAG_PLAYABLE); } - private MediaBrowserCompat.MediaItem createPlayableMediaItem(String mediaId, String title, int iconDrawableId, + private MediaBrowserCompat.MediaItem createPlayableMediaItem(String mediaId, + String title, + int iconDrawableId, @Nullable String subtitle) { MediaDescriptionCompat.Builder builder = new MediaDescriptionCompat.Builder() .setMediaId(mediaId) - .setTitle(title) - .setIconBitmap(ImageUtil.createBitmap(ImageUtil.getTintedVectorDrawable(mContext, iconDrawableId, ThemeStore.Companion.textColorSecondary(mContext)))); + .setTitle(title); if (subtitle != null) { builder.setSubtitle(subtitle); diff --git a/app/src/main/java/code/name/monkey/retromusic/auto/CarHelper.java b/app/src/main/java/code/name/monkey/retromusic/auto/CarHelper.java deleted file mode 100644 index 9c6ebd36..00000000 --- a/app/src/main/java/code/name/monkey/retromusic/auto/CarHelper.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ -package code.name.monkey.retromusic.auto; - -import android.app.UiModeManager; -import android.content.Context; -import android.content.res.Configuration; - -public class CarHelper { - - private static final String TAG = "CarHelper"; - - public static boolean isCarUiMode(Context c) { - UiModeManager uiModeManager = (UiModeManager) c.getSystemService(Context.UI_MODE_SERVICE); - return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR; - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt b/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt index dfa91487..06642b9c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MediaSessionCallback.kt @@ -92,6 +92,10 @@ class MediaSessionCallback(private val context: Context, songs.addAll(playlist.getSongs(context)) openQueue(songs, 0, true) } + AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_GENRE -> { + songs.addAll(GenreLoader.getSongs(context, itemId)) + openQueue(songs, 0, true) + } AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_HISTORY, AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_TOP_TRACKS, AutoMediaIDHelper.MEDIA_ID_MUSICS_BY_QUEUE -> { diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java index c9234377..b5913c34 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.java @@ -337,8 +337,10 @@ public class MusicService extends MediaBrowserServiceCompat implements SharedPre PreferenceUtil.getInstance().registerOnSharedPreferenceChangedListener(this); restoreState(); + mPackageValidator = new PackageValidator(this, R.xml.allowed_media_browser_callers); mMusicProvider = new AutoMusicProvider(this); + sendBroadcast(new Intent("code.name.monkey.retromusic.RETRO_MUSIC_SERVICE_CREATED")); registerHeadsetEvents(); @@ -352,19 +354,26 @@ public class MusicService extends MediaBrowserServiceCompat implements SharedPre } private void setupMediaSession() { - ComponentName mediaButtonReceiverComponentName = new ComponentName(getApplicationContext(), MediaButtonIntentReceiver.class); + ComponentName mediaButtonReceiverComponentName = new ComponentName( + getApplicationContext(), + MediaButtonIntentReceiver.class); Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.setComponent(mediaButtonReceiverComponentName); - PendingIntent mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0); + PendingIntent mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast( + getApplicationContext(), + 0, + mediaButtonIntent, + 0); mediaSession = new MediaSessionCompat(this, "RetroMusicPlayer", mediaButtonReceiverComponentName, mediaButtonReceiverPendingIntent); - MediaSessionCallback mediasessionCallback = new MediaSessionCallback(getApplicationContext(), this); + MediaSessionCallback mediasessionCallback = new MediaSessionCallback( + getApplicationContext(), this); mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS ); @@ -418,7 +427,7 @@ public class MusicService extends MediaBrowserServiceCompat implements SharedPre } } - return START_STICKY; + return START_NOT_STICKY; } private void playFromPlaylist(Intent intent) { @@ -445,21 +454,6 @@ public class MusicService extends MediaBrowserServiceCompat implements SharedPre } } - private void playSongs(int shuffleMode, ArrayList playlistSongs) { - if (!playlistSongs.isEmpty()) { - if (shuffleMode == SHUFFLE_MODE_SHUFFLE) { - int startPosition; - startPosition = new Random().nextInt(playlistSongs.size()); - openQueue(playlistSongs, startPosition, true); - setShuffleMode(shuffleMode); - } else { - openQueue(playlistSongs, 0, true); - } - } else { - Toast.makeText(getApplicationContext(), R.string.playlist_is_empty, Toast.LENGTH_LONG).show(); - } - } - @Override public void onDestroy() { unregisterReceiver(widgetIntentReceiver); @@ -478,20 +472,28 @@ public class MusicService extends MediaBrowserServiceCompat implements SharedPre PreferenceUtil.getInstance().unregisterOnSharedPreferenceChangedListener(this); wakeLock.release(); - sendBroadcast(new Intent("code.name.monkey.retromusic.RETRO_MUSIC_MUSIC_SERVICE_DESTROYED")); + sendBroadcast(new Intent("code.name.monkey.retromusic.RETRO_MUSIC_SERVICE_DESTROYED")); } @Override public IBinder onBind(Intent intent) { + // For Android auto, need to call super, or onGetRoot won't be called. + if (intent != null && "android.media.browse.MediaBrowserService".equals(intent.getAction())) { + return super.onBind(intent); + } return musicBind; } @Nullable @Override public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) { + + // Check origin to ensure we're not allowing any arbitrary app to browse app contents if (!mPackageValidator.isKnownCaller(clientPackageName, clientUid)) { + // Request from an untrusted package: return an empty browser root return new BrowserRoot(AutoMediaIDHelper.MEDIA_ID_EMPTY_ROOT, null); } + return new BrowserRoot(AutoMediaIDHelper.MEDIA_ID_ROOT, null); } @@ -686,10 +688,33 @@ public class MusicService extends MediaBrowserServiceCompat implements SharedPre .setState(isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED, getSongProgressMillis(), 1); + setCustomAction(stateBuilder); mediaSession.setPlaybackState(stateBuilder.build()); } + private void setCustomAction(PlaybackStateCompat.Builder stateBuilder) { + int repeatIcon = R.drawable.ic_repeat_white_24dp; // REPEAT_MODE_NONE + if (getRepeatMode() == REPEAT_MODE_THIS) { + repeatIcon = R.drawable.ic_repeat_one_white_24dp; + } else if (getRepeatMode() == REPEAT_MODE_ALL) { + repeatIcon = R.drawable.ic_repeat_white_24dp; + } + stateBuilder.addCustomAction(new PlaybackStateCompat.CustomAction.Builder( + CYCLE_REPEAT, getString(R.string.action_cycle_repeat), repeatIcon) + .build()); + + final int shuffleIcon = getShuffleMode() == SHUFFLE_MODE_NONE ? R.drawable.ic_shuffle_white_24dp : R.drawable.ic_shuffle_white_24dp; + stateBuilder.addCustomAction(new PlaybackStateCompat.CustomAction.Builder( + TOGGLE_SHUFFLE, getString(R.string.action_toggle_shuffle), shuffleIcon) + .build()); + + final int favoriteIcon = MusicUtil.isFavorite(getApplicationContext(), getCurrentSong()) ? R.drawable.ic_favorite_white_24dp : R.drawable.ic_favorite_border_white_24dp; + stateBuilder.addCustomAction(new PlaybackStateCompat.CustomAction.Builder( + TOGGLE_FAVORITE, getString(R.string.action_toggle_favorite), favoriteIcon) + .build()); + } + private void updateMediaSessionMetaData() { final Song song = getCurrentSong(); diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt b/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt index d6df60ad..d75bd28b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt @@ -11,8 +11,10 @@ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. */ + package code.name.monkey.retromusic.util + import android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE import android.Manifest.permission.MEDIA_CONTENT_CONTROL import android.annotation.SuppressLint @@ -45,7 +47,10 @@ import java.security.NoSuchAlgorithmException * * For more information, see res/xml/allowed_media_browser_callers.xml. */ -class PackageValidator(context: Context, @XmlRes xmlResId: Int) { +class PackageValidator( + context: Context, + @XmlRes xmlResId: Int +) { private val context: Context private val packageManager: PackageManager diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d571c0fb..a89c9027 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -191,6 +191,7 @@ Genre Genres + Genres Fork the project on GitHub diff --git a/app/src/main/res/xml/allowed_media_browser_callers.xml b/app/src/main/res/xml/allowed_media_browser_callers.xml index a8861593..2fa94b88 100644 --- a/app/src/main/res/xml/allowed_media_browser_callers.xml +++ b/app/src/main/res/xml/allowed_media_browser_callers.xml @@ -1,12 +1,9 @@ @@ -164,32 +160,6 @@ limitations under the License. BKZCvlzboOEAZfx8aBKc7SezqATXpM3ZDNPsywWoyIpgmtBWoE60ih4Flf05XB+n e7MdpSQ0Xgq9TgG1BoJP6rpC0y3Ukmc+z8AXnYYdJunNXEbv0A== - - MIIDvTCCAqWgAwIBAgIJAMePnkuTQTAGMA0GCSqGSIb3DQEBBQUAMHUxCzAJBgNV - BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW - aWV3MRQwEgYDVQQKDAtHb29nbGUgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDERMA8G - A1UEAwwIZ2VhcmhlYWQwHhcNMTQwNTI3MjMwNTM0WhcNNDExMDEyMjMwNTM0WjB1 - MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91 - bnRhaW4gVmlldzEUMBIGA1UECgwLR29vZ2xlIEluYy4xEDAOBgNVBAsMB0FuZHJv - aWQxETAPBgNVBAMMCGdlYXJoZWFkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB - CgKCAQEA050XDkNIsVRMX2wTvVplpCu4OtnyNK2v5B7PS+DggmH2yuZiwpTurdKD - Q9R9UzxH9U4lsC+mIxXkiBYKIWNVgMtiTgxkEy7cgWvdYHgNYpFu8IxZKYDyXes+ - 02pfvpu63MIBD/PnvVFipo1oUrbfetj+mroEpjnA71gUS0Ok+H6XWWsmb8xFHQVM - oZWEIzsUJ2nhm8EcnPkAPfNZAG++XLPROoRQCaswyYsd42JuYAP3CwZuhDcUbMWm - k7rBi9BVQ8gmkrbwqo94A7qStLUp3NyCmlKSWHaZ05SspEPwsfctka0oXG5bhgT6 - 67EMCzQ+YsFN1oJRL7Qq+mMQjFJs3wIDAQABo1AwTjAdBgNVHQ4EFgQUGvBfYNeu - 6JSJUnJZCiaBGsnXztswHwYDVR0jBBgwFoAUGvBfYNeu6JSJUnJZCiaBGsnXztsw - DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAlGsDY0EPu3NBSH5k6iw/ - wJh9e3xMwS17ErKGlhyWogxJMzLjAN6g0aCPHxB40IQC+8qAl+RL7VQx6oxttf0m - 31yUGQPcNYbt2CxBTCAr885oLK5t2TAi5tQzhd6ZEYihWSUWUd/X8BQRouxboss9 - QbBA/iIx0OpDaxiAcq7Cb67TheXZDxGuQ8fmHYbLx84pEvm3DQOB/LIMkkpQSfEC - 1f+oP1zB3urPU/dSvED/LCgOdrpxZ5di7SwSyue+Vq/TZQy34tPygEzD2d8hFlh/ - yfhWkMizOeIXcayVAQdNn5zpBkuay1skGOjQQ5kTbDcDzigO2R2rqn6HCd9l5Z0W - IQ== - - - MIIEqDCCA5CgAwIBAgIJANWFuGx90071MA0GCSqGSIb3DQEBBAUAMIGUMQswCQYD - VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g - VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE - AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe - Fw0wODA0MTUyMzM2NTZaFw0zNTA5MDEyMzM2NTZaMIGUMQswCQYDVQQGEwJVUzET - MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G - A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p - ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI - hvcNAQEBBQADggENADCCAQgCggEBANbOLggKv+IxTdGNs8/TGFy0PTP6DHThvbbR - 24kT9ixcOd9W+EaBPWW+wPPKQmsHxajtWjmQwWfna8mZuSeJS48LIgAZlKkpFeVy - xW0qMBujb8X8ETrWy550NaFtI6t9+u7hZeTfHwqNvacKhp1RbE6dBRGWynwMVX8X - W8N1+UjFaq6GCJukT4qmpN2afb8sCjUigq0GuMwYXrFVee74bQgLHWGJwPmvmLHC - 69EH6kWr22ijx4OKXlSIx2xT1AsSHee70w5iDBiK4aph27yH3TxkXy9V89TDdexA - cKk/cVHYNnDBapcavl7y0RiQ4biu8ymM8Ga/nmzhRKya6G0cGw8CAQOjgfwwgfkw - HQYDVR0OBBYEFI0cxb6VTEM8YYY6FbBMvAPyT+CyMIHJBgNVHSMEgcEwgb6AFI0c - xb6VTEM8YYY6FbBMvAPyT+CyoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE - CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH - QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG - CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJANWFuGx90071MAwGA1Ud - EwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADggEBABnTDPEF+3iSP0wNfdIjIz1AlnrP - zgAIHVvXxunW7SBrDhEglQZBbKJEk5kT0mtKoOD1JMrSu1xuTKEBahWRbqHsXcla - XjoBADb0kkjVEJu/Lh5hgYZnOjvlba8Ld7HCKePCVePoTJBdI4fvugnL8TsgK05a - IskyY0hKI9L8KfqfGTl1lzOv2KoWD0KWwtAWPoGChZxmQ+nBli+gwYMzM1vAkP+a - ayLe0a1EQimlOalO762r0GXO0ks+UeXde2Z4e+8S/pf7pITEI/tP+MxJTALw9QUW - Ev9lKTk+jkbqxbsh8nfBUapfKqYn0eidpwq2AzVp3juYl7//fKnaPhJD9gs= - - MIIDvTCCAqWgAwIBAgIJAMePnkuTQTAGMA0GCSqGSIb3DQEBBQUAMHUxCzAJBgNV - BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBW - aWV3MRQwEgYDVQQKDAtHb29nbGUgSW5jLjEQMA4GA1UECwwHQW5kcm9pZDERMA8G - A1UEAwwIZ2VhcmhlYWQwHhcNMTQwNTI3MjMwNTM0WhcNNDExMDEyMjMwNTM0WjB1 - MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91 - bnRhaW4gVmlldzEUMBIGA1UECgwLR29vZ2xlIEluYy4xEDAOBgNVBAsMB0FuZHJv - aWQxETAPBgNVBAMMCGdlYXJoZWFkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB - CgKCAQEA050XDkNIsVRMX2wTvVplpCu4OtnyNK2v5B7PS+DggmH2yuZiwpTurdKD - Q9R9UzxH9U4lsC+mIxXkiBYKIWNVgMtiTgxkEy7cgWvdYHgNYpFu8IxZKYDyXes+ - 02pfvpu63MIBD/PnvVFipo1oUrbfetj+mroEpjnA71gUS0Ok+H6XWWsmb8xFHQVM - oZWEIzsUJ2nhm8EcnPkAPfNZAG++XLPROoRQCaswyYsd42JuYAP3CwZuhDcUbMWm - k7rBi9BVQ8gmkrbwqo94A7qStLUp3NyCmlKSWHaZ05SspEPwsfctka0oXG5bhgT6 - 67EMCzQ+YsFN1oJRL7Qq+mMQjFJs3wIDAQABo1AwTjAdBgNVHQ4EFgQUGvBfYNeu - 6JSJUnJZCiaBGsnXztswHwYDVR0jBBgwFoAUGvBfYNeu6JSJUnJZCiaBGsnXztsw - DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAlGsDY0EPu3NBSH5k6iw/ - wJh9e3xMwS17ErKGlhyWogxJMzLjAN6g0aCPHxB40IQC+8qAl+RL7VQx6oxttf0m - 31yUGQPcNYbt2CxBTCAr885oLK5t2TAi5tQzhd6ZEYihWSUWUd/X8BQRouxboss9 - QbBA/iIx0OpDaxiAcq7Cb67TheXZDxGuQ8fmHYbLx84pEvm3DQOB/LIMkkpQSfEC - 1f+oP1zB3urPU/dSvED/LCgOdrpxZ5di7SwSyue+Vq/TZQy34tPygEzD2d8hFlh/ - yfhWkMizOeIXcayVAQdNn5zpBkuay1skGOjQQ5kTbDcDzigO2R2rqn6HCd9l5Z0W - IQ== + MIIEQzCCAyugAwIBAgIJAMLgh0ZkSjCNMA0GCSqGSIb3DQEBBAUAMHQxCzAJBgNV + BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBW + aWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9pZDEQMA4G + A1UEAxMHQW5kcm9pZDAeFw0wODA4MjEyMzEzMzRaFw0zNjAxMDcyMzEzMzRaMHQx + CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3Vu + dGFpbiBWaWV3MRQwEgYDVQQKEwtHb29nbGUgSW5jLjEQMA4GA1UECxMHQW5kcm9p + ZDEQMA4GA1UEAxMHQW5kcm9pZDCCASAwDQYJKoZIhvcNAQEBBQADggENADCCAQgC + ggEBAKtWLgDYO6IIrgqWbxJOKdoR8qtW0I9Y4sypEwPpt1TTcvZApxsdyxMJZ2JO + Rland2qSGT2y5b+3JKkedxiLDmpHpDsz2WCbdxgxRczfey5YZnTJ4VZbH0xqWVW/ + 8lGmPav5xVwnIiJS6HXk+BVKZF+JcWjAsb/GEuq/eFdpuzSqeYTcfi6idkyugwfY + wXFU1+5fZKUaRKYCwkkFQVfcAs1fXA5V+++FGfvjJ/CxURaSxaBvGdGDhfXE28LW + uT9ozCl5xw4Yq5OGazvV24mZVSoOO0yZ31j7kYvtwYK6NeADwbSxDdJEqO4k//0z + OHKrUiGYXtqw/A0LFFtqoZKFjnkCAQOjgdkwgdYwHQYDVR0OBBYEFMd9jMIhF1Yl + mn/Tgt9r45jk14alMIGmBgNVHSMEgZ4wgZuAFMd9jMIhF1Ylmn/Tgt9r45jk14al + oXikdjB0MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UE + BxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLR29vZ2xlIEluYy4xEDAOBgNVBAsT + B0FuZHJvaWQxEDAOBgNVBAMTB0FuZHJvaWSCCQDC4IdGZEowjTAMBgNVHRMEBTAD + AQH/MA0GCSqGSIb3DQEBBAUAA4IBAQBt0lLO74UwLDYKqs6Tm8/yzKkEu116FmH4 + rkaymUIE0P9KaMftGlMexFlaYjzmB2OxZyl6euNXEsQH8gjwyxCUKRJNexBiGcCE + yj6z+a1fuHHvkiaai+KL8W1EyNmgjmyy8AW7P+LLlkR+ho5zEHatRbM/YAnqGcFh + 5iZBqpknHf1SKMXFh4dd239FJ1jWYfbMDMy3NS5CTMQ2XFI1MvcyUTdZPErjQfTb + Qe3aDQsQcafEQPD+nqActifKZ0Np0IS9L9kR/wbNvyz6ENwPiTrjV2KRkEjH78ZM + cUQXg0L3BYHJ3lc69Vs5Ddf9uUGGMYldX3WfMBEmh/9iFBDAaTCK \ No newline at end of file