Merge branch 'develop' into remove-mediastore

This commit is contained in:
Nite 2021-05-05 09:41:09 +02:00 committed by GitHub
commit 83b186b9b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 932 additions and 913 deletions

View File

@ -33,7 +33,7 @@
<ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled &amp;&amp; !deleteEnabled &amp;&amp; !isOffline(context)</ID> <ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled &amp;&amp; !deleteEnabled &amp;&amp; !isOffline(context)</ID>
<ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled &amp;&amp; !isOffline(context) &amp;&amp; selection.size &gt; pinnedCount</ID> <ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled &amp;&amp; !isOffline(context) &amp;&amp; selection.size &gt; pinnedCount</ID>
<ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$entry != null &amp;&amp; !entry.isDirectory &amp;&amp; !entry.isVideo</ID> <ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$entry != null &amp;&amp; !entry.isDirectory &amp;&amp; !entry.isVideo</ID>
<ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment.&lt;no name provided&gt;$Util.getShouldShowAllSongsByArtist(context) &amp;&amp; musicDirectory.findChild(allSongsId) == null &amp;&amp; musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size</ID> <ID>ComplexCondition:SelectAlbumModel.kt$SelectAlbumModel$Util.getShouldShowAllSongsByArtist(context) &amp;&amp; musicDirectory.findChild(allSongsId) == null &amp;&amp; musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size</ID>
<ID>ComplexCondition:ServerSettingsModel.kt$ServerSettingsModel$url.isNullOrEmpty() || userName.isNullOrEmpty() || isMigrated</ID> <ID>ComplexCondition:ServerSettingsModel.kt$ServerSettingsModel$url.isNullOrEmpty() || userName.isNullOrEmpty() || isMigrated</ID>
<ID>ComplexCondition:SongView.kt$SongView$TextUtils.isEmpty(transcodedSuffix) || transcodedSuffix == suffix || song.isVideo &amp;&amp; Util.getVideoPlayerType(this.context) !== VideoPlayerType.FLASH</ID> <ID>ComplexCondition:SongView.kt$SongView$TextUtils.isEmpty(transcodedSuffix) || transcodedSuffix == suffix || song.isVideo &amp;&amp; Util.getVideoPlayerType(this.context) !== VideoPlayerType.FLASH</ID>
<ID>ComplexCondition:SubsonicImageLoaderProxy.kt$SubsonicImageLoaderProxy$id != null &amp;&amp; view != null &amp;&amp; view is ImageView</ID> <ID>ComplexCondition:SubsonicImageLoaderProxy.kt$SubsonicImageLoaderProxy$id != null &amp;&amp; view != null &amp;&amp; view is ImageView</ID>
@ -49,10 +49,9 @@
<ID>ComplexMethod:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()</ID> <ID>ComplexMethod:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()</ID>
<ID>ComplexMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String</ID> <ID>ComplexMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String</ID>
<ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID> <ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID>
<ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
<ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()</ID> <ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()</ID>
<ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)</ID> <ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)</ID>
<ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair&lt;MusicDirectory, Boolean&gt;)</ID> <ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory)</ID>
<ID>ComplexMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID> <ID>ComplexMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
<ID>ComplexMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?</ID> <ID>ComplexMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?</ID>
<ID>ComplexMethod:SongView.kt$SongView$fun setSong(song: MusicDirectory.Entry, checkable: Boolean, draggable: Boolean)</ID> <ID>ComplexMethod:SongView.kt$SongView$fun setSong(song: MusicDirectory.Entry, checkable: Boolean, draggable: Boolean)</ID>
@ -85,9 +84,9 @@
<ID>LargeClass:NavigationActivity.kt$NavigationActivity : AppCompatActivity</ID> <ID>LargeClass:NavigationActivity.kt$NavigationActivity : AppCompatActivity</ID>
<ID>LargeClass:RESTMusicService.kt$RESTMusicService : MusicService</ID> <ID>LargeClass:RESTMusicService.kt$RESTMusicService : MusicService</ID>
<ID>LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment : Fragment</ID> <ID>LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment : Fragment</ID>
<ID>LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment$LoadTask : FragmentBackgroundTask</ID> <ID>LargeClass:SelectAlbumModel.kt$SelectAlbumModel : AndroidViewModelKoinComponent</ID>
<ID>LargeClass:SelectArtistFragment.kt$SelectArtistFragment : Fragment</ID> <ID>LargeClass:SelectArtistFragment.kt$SelectArtistFragment : Fragment</ID>
<ID>LargeClass:ServerSettingsModel.kt$ServerSettingsModel : ViewModel</ID> <ID>LargeClass:ServerSettingsModel.kt$ServerSettingsModel : AndroidViewModel</ID>
<ID>LargeClass:SongView.kt$SongView : UpdateViewCheckable</ID> <ID>LargeClass:SongView.kt$SongView : UpdateViewCheckable</ID>
<ID>LongMethod:APIMusicDirectoryConverter.kt$fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry</ID> <ID>LongMethod:APIMusicDirectoryConverter.kt$fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry</ID>
<ID>LongMethod:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting</ID> <ID>LongMethod:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting</ID>
@ -140,14 +139,16 @@
<ID>LongMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String</ID> <ID>LongMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun createHeader( entries: List&lt;MusicDirectory.Entry&gt;, name: CharSequence?, songCount: Int ): View?</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun downloadBackground(save: Boolean, songs: List&lt;MusicDirectory.Entry?&gt;)</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun downloadBackground(save: Boolean, songs: List&lt;MusicDirectory.Entry?&gt;)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun playAll(shuffle: Boolean = false, append: Boolean = false)</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun playAll(shuffle: Boolean = false, append: Boolean = false)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.&lt;no name provided&gt;$override fun done(result: Pair&lt;MusicDirectory, Boolean&gt;)</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.&lt;no name provided&gt;$override fun load(service: MusicService): MusicDirectory</ID> <ID>LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected fun createHeader( entries: List&lt;MusicDirectory.Entry&gt;, name: CharSequence?, songCount: Int ): View?</ID> <ID>LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbumList(albumListType: String, size: Int, offset: Int)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair&lt;MusicDirectory, Boolean&gt;)</ID> <ID>LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getArtist(refresh: Boolean, id: String?, name: String?)</ID>
<ID>LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getMusicDirectory( refresh: Boolean, id: String?, name: String?, parentId: String? )</ID>
<ID>LongMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID> <ID>LongMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
<ID>LongMethod:SelectArtistFragment.kt$SelectArtistFragment$private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean</ID> <ID>LongMethod:SelectArtistFragment.kt$SelectArtistFragment$private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean</ID>
<ID>LongMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?</ID> <ID>LongMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?</ID>
@ -204,7 +205,6 @@
<ID>MagicNumber:RESTMusicService.kt$RESTMusicService$206</ID> <ID>MagicNumber:RESTMusicService.kt$RESTMusicService$206</ID>
<ID>MagicNumber:RESTMusicService.kt$RESTMusicService$5</ID> <ID>MagicNumber:RESTMusicService.kt$RESTMusicService$5</ID>
<ID>MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment$10</ID> <ID>MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment$10</ID>
<ID>MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$10</ID>
<ID>MagicNumber:SelectMusicFolderView.kt$SelectMusicFolderView$10</ID> <ID>MagicNumber:SelectMusicFolderView.kt$SelectMusicFolderView$10</ID>
<ID>MagicNumber:SongView.kt$SongView$3</ID> <ID>MagicNumber:SongView.kt$SongView$3</ID>
<ID>MagicNumber:SongView.kt$SongView$4</ID> <ID>MagicNumber:SongView.kt$SongView$4</ID>
@ -212,7 +212,6 @@
<ID>NestedBlockDepth:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()</ID> <ID>NestedBlockDepth:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()</ID>
<ID>NestedBlockDepth:DownloadHandler.kt$DownloadHandler$private fun downloadRecursively( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )</ID> <ID>NestedBlockDepth:DownloadHandler.kt$DownloadHandler$private fun downloadRecursively( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )</ID>
<ID>NestedBlockDepth:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()</ID> <ID>NestedBlockDepth:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()</ID>
<ID>NestedBlockDepth:SelectAlbumFragment.kt$SelectAlbumFragment$private fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?)</ID>
<ID>ReturnCount:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting</ID> <ID>ReturnCount:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting</ID>
<ID>ReturnCount:CommunicationErrorHandler.kt$CommunicationErrorHandler.Companion$fun getErrorMessage(error: Throwable, context: Context): String</ID> <ID>ReturnCount:CommunicationErrorHandler.kt$CommunicationErrorHandler.Companion$fun getErrorMessage(error: Throwable, context: Context): String</ID>
<ID>ReturnCount:FileLoggerTree.kt$FileLoggerTree$ private fun getNextLogFile()</ID> <ID>ReturnCount:FileLoggerTree.kt$FileLoggerTree$ private fun getNextLogFile()</ID>
@ -241,7 +240,6 @@
<ID>TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer.PositionCache$e: Exception</ID> <ID>TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer.PositionCache$e: Exception</ID>
<ID>TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$e: Exception</ID> <ID>TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$e: Exception</ID>
<ID>TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$x: IndexOutOfBoundsException</ID> <ID>TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$x: IndexOutOfBoundsException</ID>
<ID>TooGenericExceptionCaught:SelectAlbumFragment.kt$SelectAlbumFragment$exception: Exception</ID>
<ID>TooGenericExceptionCaught:SongView.kt$SongView$e: Exception</ID> <ID>TooGenericExceptionCaught:SongView.kt$SongView$e: Exception</ID>
<ID>TooGenericExceptionCaught:SubsonicUncaughtExceptionHandler.kt$SubsonicUncaughtExceptionHandler$x: Throwable</ID> <ID>TooGenericExceptionCaught:SubsonicUncaughtExceptionHandler.kt$SubsonicUncaughtExceptionHandler$x: Throwable</ID>
<ID>TooGenericExceptionCaught:VideoPlayer.kt$VideoPlayer$e: Exception</ID> <ID>TooGenericExceptionCaught:VideoPlayer.kt$VideoPlayer$e: Exception</ID>

View File

@ -33,7 +33,7 @@
<ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled &amp;&amp; !deleteEnabled &amp;&amp; !isOffline(context)</ID> <ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled &amp;&amp; !deleteEnabled &amp;&amp; !isOffline(context)</ID>
<ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled &amp;&amp; !isOffline(context) &amp;&amp; selection.size &gt; pinnedCount</ID> <ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled &amp;&amp; !isOffline(context) &amp;&amp; selection.size &gt; pinnedCount</ID>
<ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$entry != null &amp;&amp; !entry.isDirectory &amp;&amp; !entry.isVideo</ID> <ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$entry != null &amp;&amp; !entry.isDirectory &amp;&amp; !entry.isVideo</ID>
<ID>ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment.&lt;no name provided&gt;$Util.getShouldShowAllSongsByArtist(context) &amp;&amp; musicDirectory.findChild(allSongsId) == null &amp;&amp; musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size</ID> <ID>ComplexCondition:SelectAlbumModel.kt$SelectAlbumModel$Util.getShouldShowAllSongsByArtist(context) &amp;&amp; musicDirectory.findChild(allSongsId) == null &amp;&amp; musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size</ID>
<ID>ComplexCondition:ServerSettingsModel.kt$ServerSettingsModel$url.isNullOrEmpty() || userName.isNullOrEmpty() || isMigrated</ID> <ID>ComplexCondition:ServerSettingsModel.kt$ServerSettingsModel$url.isNullOrEmpty() || userName.isNullOrEmpty() || isMigrated</ID>
<ID>ComplexCondition:SongView.kt$SongView$TextUtils.isEmpty(transcodedSuffix) || transcodedSuffix == suffix || song.isVideo &amp;&amp; Util.getVideoPlayerType(this.context) !== VideoPlayerType.FLASH</ID> <ID>ComplexCondition:SongView.kt$SongView$TextUtils.isEmpty(transcodedSuffix) || transcodedSuffix == suffix || song.isVideo &amp;&amp; Util.getVideoPlayerType(this.context) !== VideoPlayerType.FLASH</ID>
<ID>ComplexCondition:SubsonicImageLoaderProxy.kt$SubsonicImageLoaderProxy$id != null &amp;&amp; view != null &amp;&amp; view is ImageView</ID> <ID>ComplexCondition:SubsonicImageLoaderProxy.kt$SubsonicImageLoaderProxy$id != null &amp;&amp; view != null &amp;&amp; view is ImageView</ID>
@ -49,10 +49,11 @@
<ID>ComplexMethod:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()</ID> <ID>ComplexMethod:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()</ID>
<ID>ComplexMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String</ID> <ID>ComplexMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String</ID>
<ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID> <ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID>
<ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
<ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()</ID> <ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()</ID>
<ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)</ID> <ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)</ID>
<ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair&lt;MusicDirectory, Boolean&gt;)</ID> <ID>ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory)</ID>
<ID>ComplexMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbumList(albumListType: String, size: Int, offset: Int)</ID>
<ID>ComplexMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getMusicDirectory( refresh: Boolean, id: String?, name: String?, parentId: String? )</ID>
<ID>ComplexMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID> <ID>ComplexMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
<ID>ComplexMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?</ID> <ID>ComplexMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?</ID>
<ID>ComplexMethod:SongView.kt$SongView$fun setSong(song: MusicDirectory.Entry, checkable: Boolean, draggable: Boolean)</ID> <ID>ComplexMethod:SongView.kt$SongView$fun setSong(song: MusicDirectory.Entry, checkable: Boolean, draggable: Boolean)</ID>
@ -85,9 +86,9 @@
<ID>LargeClass:NavigationActivity.kt$NavigationActivity : AppCompatActivity</ID> <ID>LargeClass:NavigationActivity.kt$NavigationActivity : AppCompatActivity</ID>
<ID>LargeClass:RESTMusicService.kt$RESTMusicService : MusicService</ID> <ID>LargeClass:RESTMusicService.kt$RESTMusicService : MusicService</ID>
<ID>LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment : Fragment</ID> <ID>LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment : Fragment</ID>
<ID>LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment$LoadTask : FragmentBackgroundTask</ID> <ID>LargeClass:SelectAlbumModel.kt$SelectAlbumModel : AndroidViewModelKoinComponent</ID>
<ID>LargeClass:SelectArtistFragment.kt$SelectArtistFragment : Fragment</ID> <ID>LargeClass:SelectArtistFragment.kt$SelectArtistFragment : Fragment</ID>
<ID>LargeClass:ServerSettingsModel.kt$ServerSettingsModel : ViewModel</ID> <ID>LargeClass:ServerSettingsModel.kt$ServerSettingsModel : AndroidViewModel</ID>
<ID>LargeClass:SongView.kt$SongView : UpdateViewCheckable</ID> <ID>LargeClass:SongView.kt$SongView : UpdateViewCheckable</ID>
<ID>LongMethod:APIMusicDirectoryConverter.kt$fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry</ID> <ID>LongMethod:APIMusicDirectoryConverter.kt$fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry</ID>
<ID>LongMethod:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting</ID> <ID>LongMethod:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting</ID>
@ -140,14 +141,16 @@
<ID>LongMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String</ID> <ID>LongMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun createHeader( entries: List&lt;MusicDirectory.Entry&gt;, name: CharSequence?, songCount: Int ): View?</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun downloadBackground(save: Boolean, songs: List&lt;MusicDirectory.Entry?&gt;)</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun downloadBackground(save: Boolean, songs: List&lt;MusicDirectory.Entry?&gt;)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons()</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun playAll(shuffle: Boolean = false, append: Boolean = false)</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun playAll(shuffle: Boolean = false, append: Boolean = false)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.&lt;no name provided&gt;$override fun done(result: Pair&lt;MusicDirectory, Boolean&gt;)</ID> <ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.&lt;no name provided&gt;$override fun load(service: MusicService): MusicDirectory</ID> <ID>LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected fun createHeader( entries: List&lt;MusicDirectory.Entry&gt;, name: CharSequence?, songCount: Int ): View?</ID> <ID>LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbumList(albumListType: String, size: Int, offset: Int)</ID>
<ID>LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair&lt;MusicDirectory, Boolean&gt;)</ID> <ID>LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getArtist(refresh: Boolean, id: String?, name: String?)</ID>
<ID>LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getMusicDirectory( refresh: Boolean, id: String?, name: String?, parentId: String? )</ID>
<ID>LongMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID> <ID>LongMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?)</ID>
<ID>LongMethod:SelectArtistFragment.kt$SelectArtistFragment$private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean</ID> <ID>LongMethod:SelectArtistFragment.kt$SelectArtistFragment$private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean</ID>
<ID>LongMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?</ID> <ID>LongMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View?</ID>
@ -204,7 +207,6 @@
<ID>MagicNumber:RESTMusicService.kt$RESTMusicService$206</ID> <ID>MagicNumber:RESTMusicService.kt$RESTMusicService$206</ID>
<ID>MagicNumber:RESTMusicService.kt$RESTMusicService$5</ID> <ID>MagicNumber:RESTMusicService.kt$RESTMusicService$5</ID>
<ID>MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment$10</ID> <ID>MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment$10</ID>
<ID>MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$10</ID>
<ID>MagicNumber:SelectMusicFolderView.kt$SelectMusicFolderView$10</ID> <ID>MagicNumber:SelectMusicFolderView.kt$SelectMusicFolderView$10</ID>
<ID>MagicNumber:SongView.kt$SongView$3</ID> <ID>MagicNumber:SongView.kt$SongView$3</ID>
<ID>MagicNumber:SongView.kt$SongView$4</ID> <ID>MagicNumber:SongView.kt$SongView$4</ID>
@ -212,7 +214,6 @@
<ID>NestedBlockDepth:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()</ID> <ID>NestedBlockDepth:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute()</ID>
<ID>NestedBlockDepth:DownloadHandler.kt$DownloadHandler$private fun downloadRecursively( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )</ID> <ID>NestedBlockDepth:DownloadHandler.kt$DownloadHandler$private fun downloadRecursively( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean )</ID>
<ID>NestedBlockDepth:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()</ID> <ID>NestedBlockDepth:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler()</ID>
<ID>NestedBlockDepth:SelectAlbumFragment.kt$SelectAlbumFragment$private fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?)</ID>
<ID>ReturnCount:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting</ID> <ID>ReturnCount:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting</ID>
<ID>ReturnCount:CommunicationErrorHandler.kt$CommunicationErrorHandler.Companion$fun getErrorMessage(error: Throwable, context: Context): String</ID> <ID>ReturnCount:CommunicationErrorHandler.kt$CommunicationErrorHandler.Companion$fun getErrorMessage(error: Throwable, context: Context): String</ID>
<ID>ReturnCount:FileLoggerTree.kt$FileLoggerTree$ private fun getNextLogFile()</ID> <ID>ReturnCount:FileLoggerTree.kt$FileLoggerTree$ private fun getNextLogFile()</ID>
@ -241,7 +242,6 @@
<ID>TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer.PositionCache$e: Exception</ID> <ID>TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer.PositionCache$e: Exception</ID>
<ID>TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$e: Exception</ID> <ID>TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$e: Exception</ID>
<ID>TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$x: IndexOutOfBoundsException</ID> <ID>TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$x: IndexOutOfBoundsException</ID>
<ID>TooGenericExceptionCaught:SelectAlbumFragment.kt$SelectAlbumFragment$exception: Exception</ID>
<ID>TooGenericExceptionCaught:SongView.kt$SongView$e: Exception</ID> <ID>TooGenericExceptionCaught:SongView.kt$SongView$e: Exception</ID>
<ID>TooGenericExceptionCaught:SubsonicUncaughtExceptionHandler.kt$SubsonicUncaughtExceptionHandler$x: Throwable</ID> <ID>TooGenericExceptionCaught:SubsonicUncaughtExceptionHandler.kt$SubsonicUncaughtExceptionHandler$x: Throwable</ID>
<ID>TooGenericExceptionCaught:VideoPlayer.kt$VideoPlayer$e: Exception</ID> <ID>TooGenericExceptionCaught:VideoPlayer.kt$VideoPlayer$e: Exception</ID>

View File

@ -49,8 +49,6 @@ complexity:
thresholdInFiles: 20 thresholdInFiles: 20
thresholdInClasses: 20 thresholdInClasses: 20
thresholdInInterfaces: 20 thresholdInInterfaces: 20
ComplexCondition:
threshold: 3
LabeledExpression: LabeledExpression:
active: false active: false

View File

@ -492,13 +492,8 @@ public class SettingsFragment extends PreferenceFragmentCompat
} }
private void setMediaButtonsEnabled(boolean enabled) { private void setMediaButtonsEnabled(boolean enabled) {
if (enabled) { lockScreenEnabled.setEnabled(enabled);
lockScreenEnabled.setEnabled(true); Util.updateMediaButtonEventReceiver();
Util.registerMediaButtonEventReceiver(getActivity(), false);
} else {
lockScreenEnabled.setEnabled(false);
Util.unregisterMediaButtonEventReceiver(getActivity(), false);
}
} }
private void setBluetoothPreferences(boolean enabled) { private void setBluetoothPreferences(boolean enabled) {

View File

@ -29,7 +29,7 @@ import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.Util; import org.moire.ultrasonic.util.Util;
/** /**
* Request media button focus when connected to Bluetooth A2DP. * Resume or pause playback on Bluetooth A2DP connect/disconnect.
* *
* @author Sindre Mehus * @author Sindre Mehus
*/ */
@ -63,7 +63,6 @@ public class BluetoothIntentReceiver extends BroadcastReceiver
if (state == android.bluetooth.BluetoothA2dp.STATE_CONNECTED) actionA2dpConnected = true; if (state == android.bluetooth.BluetoothA2dp.STATE_CONNECTED) actionA2dpConnected = true;
else if (state == android.bluetooth.BluetoothA2dp.STATE_DISCONNECTED) actionA2dpDisconnected = true; else if (state == android.bluetooth.BluetoothA2dp.STATE_DISCONNECTED) actionA2dpDisconnected = true;
boolean connected = actionA2dpConnected || actionBluetoothDeviceConnected;
boolean resume = false; boolean resume = false;
boolean pause = false; boolean pause = false;
@ -83,12 +82,6 @@ public class BluetoothIntentReceiver extends BroadcastReceiver
break; break;
} }
if (connected)
{
Timber.i("Connected to Bluetooth device %s address %s, requesting media button focus.", name, address);
Util.registerMediaButtonEventReceiver(context, false);
}
if (resume) if (resume)
{ {
Timber.i("Connected to Bluetooth device %s address %s, resuming playback.", name, address); Timber.i("Connected to Bluetooth device %s address %s, resuming playback.", name, address);

View File

@ -46,7 +46,7 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver
String intentAction = intent.getAction(); String intentAction = intent.getAction();
// If media button are turned off and we received a media button, exit // If media button are turned off and we received a media button, exit
if (!Util.getMediaButtonsPreference(context) && if (!Util.getMediaButtonsEnabled(context) &&
Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) return; Intent.ACTION_MEDIA_BUTTON.equals(intentAction)) return;
// Only process media buttons and CMD_PROCESS_KEYCODE, which is received from the widgets // Only process media buttons and CMD_PROCESS_KEYCODE, which is received from the widgets

View File

@ -85,12 +85,7 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
public void onCreate() public void onCreate()
{ {
if (created) return; if (created) return;
this.externalStorageMonitor.onCreate(new Runnable() { this.externalStorageMonitor.onCreate(this::reset);
@Override
public void run() {
reset();
}
});
setJukeboxEnabled(activeServerProvider.getValue().getActiveServer().getJukeboxByDefault()); setJukeboxEnabled(activeServerProvider.getValue().getActiveServer().getJukeboxByDefault());
created = true; created = true;
@ -116,9 +111,8 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
if (currentPlayingIndex != -1) if (currentPlayingIndex != -1)
{ {
MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) ->
@Override {
public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.play(currentPlayingIndex, autoPlayStart); mediaPlayerService.play(currentPlayingIndex, autoPlayStart);
if (localMediaPlayer.currentPlaying != null) if (localMediaPlayer.currentPlaying != null)
@ -136,8 +130,9 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
} }
} }
autoPlayStart = false; autoPlayStart = false;
} return null;
}); }
);
} }
} }
@ -149,55 +144,53 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
@Override @Override
public synchronized void play(final int index) public synchronized void play(final int index)
{ {
MediaPlayerService.executeOnStartedMediaPlayerService(context,new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> {
@Override
public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.play(index, true); mediaPlayerService.play(index, true);
} return null;
}); }
);
} }
public synchronized void play() public synchronized void play()
{ {
MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> {
@Override
public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.play(); mediaPlayerService.play();
} return null;
}); }
);
} }
public synchronized void resumeOrPlay() public synchronized void resumeOrPlay()
{ {
MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> {
@Override
public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.resumeOrPlay(); mediaPlayerService.resumeOrPlay();
} return null;
}); }
);
} }
@Override @Override
public synchronized void togglePlayPause() public synchronized void togglePlayPause()
{ {
if (localMediaPlayer.playerState == PlayerState.IDLE) autoPlayStart = true; if (localMediaPlayer.playerState == PlayerState.IDLE) autoPlayStart = true;
MediaPlayerService.executeOnStartedMediaPlayerService(context,new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> {
@Override
public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.togglePlayPause(); mediaPlayerService.togglePlayPause();
} return null;
}); }
);
} }
@Override @Override
public synchronized void start() public synchronized void start()
{ {
MediaPlayerService.executeOnStartedMediaPlayerService(context, new Consumer<MediaPlayerService>() { MediaPlayerService.executeOnStartedMediaPlayerService(context, (mediaPlayerService) -> {
@Override
public void accept(MediaPlayerService mediaPlayerService) {
mediaPlayerService.start(); mediaPlayerService.start();
} return null;
}); }
);
} }
@Override @Override
@ -612,19 +605,14 @@ public class MediaPlayerControllerImpl implements MediaPlayerController
final Entry song = localMediaPlayer.currentPlaying.getSong(); final Entry song = localMediaPlayer.currentPlaying.getSong();
song.setUserRating(rating); song.setUserRating(rating);
new Thread(new Runnable() new Thread(() -> {
{ try
@Override
public void run()
{ {
try MusicServiceFactory.getMusicService(context).setRating(song.getId(), rating, context);
{ }
MusicServiceFactory.getMusicService(context).setRating(song.getId(), rating, context); catch (Exception e)
} {
catch (Exception e) Timber.e(e);
{
Timber.e(e);
}
} }
}).start(); }).start();

View File

@ -76,9 +76,6 @@ public class MediaPlayerLifecycleSupport
registerHeadsetReceiver(); registerHeadsetReceiver();
// React to media buttons.
Util.registerMediaButtonEventReceiver(context, true);
mediaPlayerController.onCreate(); mediaPlayerController.onCreate();
if (autoPlay) mediaPlayerController.preload(); if (autoPlay) mediaPlayerController.preload();

View File

@ -31,7 +31,6 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.ConnectivityManager; import android.net.ConnectivityManager;
import android.net.NetworkInfo; import android.net.NetworkInfo;
import android.net.Uri; import android.net.Uri;
@ -54,8 +53,8 @@ import org.moire.ultrasonic.R;
import org.moire.ultrasonic.data.ActiveServerProvider; import org.moire.ultrasonic.data.ActiveServerProvider;
import org.moire.ultrasonic.domain.*; import org.moire.ultrasonic.domain.*;
import org.moire.ultrasonic.domain.MusicDirectory.Entry; import org.moire.ultrasonic.domain.MusicDirectory.Entry;
import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver;
import org.moire.ultrasonic.service.DownloadFile; import org.moire.ultrasonic.service.DownloadFile;
import org.moire.ultrasonic.service.MediaPlayerService;
import java.io.*; import java.io.*;
import java.security.MessageDigest; import java.security.MessageDigest;
@ -679,31 +678,16 @@ public class Util
return Bitmap.createScaledBitmap(bitmap, size, getScaledHeight(bitmap, size), true); return Bitmap.createScaledBitmap(bitmap, size, getScaledHeight(bitmap, size), true);
} }
public static void registerMediaButtonEventReceiver(Context context, boolean isService) // Trigger an update on the MediaSession. Depending on the preference it will register
// or deregister the MediaButtonReceiver.
public static void updateMediaButtonEventReceiver()
{ {
if (getMediaButtonsPreference(context)) MediaPlayerService mediaPlayerService = MediaPlayerService.getRunningInstance();
{ if (mediaPlayerService != null) {
if (isService) mediaButtonsRegisteredForService = true; mediaPlayerService.updateMediaButtonReceiver();
else mediaButtonsRegisteredForUI = true;
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
audioManager.registerMediaButtonEventReceiver(new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName()));
} }
} }
public static void unregisterMediaButtonEventReceiver(Context context, boolean isService)
{
if (isService) mediaButtonsRegisteredForService = false;
else mediaButtonsRegisteredForUI = false;
// Do not unregister while there is an active part of the app which needs the control
if (mediaButtonsRegisteredForService || mediaButtonsRegisteredForUI) return;
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
audioManager.unregisterMediaButtonEventReceiver(new ComponentName(context.getPackageName(), MediaButtonIntentReceiver.class.getName()));
Timber.i("MediaButtonEventReceiver unregistered.");
}
public static MusicDirectory getSongsFromSearchResult(SearchResult searchResult) public static MusicDirectory getSongsFromSearchResult(SearchResult searchResult)
{ {
MusicDirectory musicDirectory = new MusicDirectory(); MusicDirectory musicDirectory = new MusicDirectory();
@ -1056,7 +1040,7 @@ public class Util
return Integer.parseInt(preferences.getString(Constants.PREFERENCES_KEY_INCREMENT_TIME, "5")); return Integer.parseInt(preferences.getString(Constants.PREFERENCES_KEY_INCREMENT_TIME, "5"));
} }
public static boolean getMediaButtonsPreference(Context context) public static boolean getMediaButtonsEnabled(Context context)
{ {
SharedPreferences preferences = getPreferences(context); SharedPreferences preferences = getPreferences(context);
return preferences.getBoolean(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true); return preferences.getBoolean(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true);

View File

@ -33,6 +33,8 @@ import org.moire.ultrasonic.util.ImageLoader;
import java.util.List; import java.util.List;
/** /**
* This is the adapter for the display of a single list item (song, album, etc)
*
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class EntryAdapter extends ArrayAdapter<Entry> public class EntryAdapter extends ArrayAdapter<Entry>

View File

@ -14,6 +14,11 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.WeakHashMap; import java.util.WeakHashMap;
/**
* A View that is periodically refreshed
* @deprecated
* Use LiveData to ensure that the content is up-to-date
**/
public class UpdateView extends LinearLayout public class UpdateView extends LinearLayout
{ {
private static final WeakHashMap<UpdateView, ?> INSTANCES = new WeakHashMap<UpdateView, Object>(); private static final WeakHashMap<UpdateView, ?> INSTANCES = new WeakHashMap<UpdateView, Object>();

View File

@ -178,7 +178,7 @@ class NavigationActivity : AppCompatActivity() {
super.onResume() super.onResume()
setMenuForServerSetting() setMenuForServerSetting()
Util.registerMediaButtonEventReceiver(this, false)
// Lifecycle support's constructor registers some event receivers so it should be created early // Lifecycle support's constructor registers some event receivers so it should be created early
lifecycleSupport.onCreate() lifecycleSupport.onCreate()
@ -188,7 +188,6 @@ class NavigationActivity : AppCompatActivity() {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
Util.unregisterMediaButtonEventReceiver(this, false)
nowPlayingEventDistributor.unsubscribe(nowPlayingEventListener) nowPlayingEventDistributor.unsubscribe(nowPlayingEventListener)
themeChangedEventDistributor.unsubscribe(themeChangedEventListener) themeChangedEventDistributor.unsubscribe(themeChangedEventListener)
imageLoaderProvider.clearImageLoader() imageLoaderProvider.clearImageLoader()
@ -310,7 +309,6 @@ class NavigationActivity : AppCompatActivity() {
private fun exit() { private fun exit() {
lifecycleSupport.onDestroy() lifecycleSupport.onDestroy()
Util.unregisterMediaButtonEventReceiver(this, false)
finish() finish()
} }

View File

@ -31,5 +31,5 @@ val appPermanentStorage = module {
single { get<AppDatabase>().serverSettingDao() } single { get<AppDatabase>().serverSettingDao() }
viewModel { ServerSettingsModel(get(), get(), androidContext()) } viewModel { ServerSettingsModel(get(), get(), get()) }
} }

View File

@ -0,0 +1,351 @@
package org.moire.ultrasonic.fragment
import android.app.Application
import android.content.Context
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import java.util.LinkedList
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.koin.core.component.KoinApiExtension
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.moire.ultrasonic.R
import org.moire.ultrasonic.api.subsonic.models.AlbumListType
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.service.MusicServiceFactory
import org.moire.ultrasonic.util.Util
// TODO: Break up this class into smaller more specific classes, extending a base class if necessary
@KoinApiExtension
class SelectAlbumModel(application: Application) : AndroidViewModel(application), KoinComponent {
private val context: Context
get() = getApplication<Application>().applicationContext
private val activeServerProvider: ActiveServerProvider by inject()
private val allSongsId = "-1"
val musicFolders: MutableLiveData<List<MusicFolder>> = MutableLiveData()
val albumList: MutableLiveData<MusicDirectory> = MutableLiveData()
val currentDirectory: MutableLiveData<MusicDirectory> = MutableLiveData()
val songsForGenre: MutableLiveData<MusicDirectory> = MutableLiveData()
var currentDirectoryIsSortable = true
var showHeader = true
var showSelectFolderHeader = false
suspend fun getMusicFolders(refresh: Boolean) {
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val musicService = MusicServiceFactory.getMusicService(context)
musicFolders.postValue(musicService.getMusicFolders(refresh, context))
}
}
}
suspend fun getMusicDirectory(
refresh: Boolean,
id: String?,
name: String?,
parentId: String?
) {
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val service = MusicServiceFactory.getMusicService(context)
var root = MusicDirectory()
if (allSongsId == id) {
val musicDirectory = service.getMusicDirectory(
parentId, name, refresh, context
)
val songs: MutableList<MusicDirectory.Entry> = LinkedList()
getSongsRecursively(musicDirectory, songs)
for (song in songs) {
if (!song.isDirectory) {
root.addChild(song)
}
}
} else {
val musicDirectory = service.getMusicDirectory(id, name, refresh, context)
if (Util.getShouldShowAllSongsByArtist(context) &&
musicDirectory.findChild(allSongsId) == null &&
hasOnlyFolders(musicDirectory)
) {
val allSongs = MusicDirectory.Entry()
allSongs.isDirectory = true
allSongs.artist = name
allSongs.parent = id
allSongs.id = allSongsId
allSongs.title = String.format(
context.resources.getString(R.string.select_album_all_songs), name
)
root.addChild(allSongs)
root.addAll(musicDirectory.getChildren())
} else {
root = musicDirectory
}
}
currentDirectory.postValue(root)
}
}
}
// Given a Music directory "songs" it recursively adds all children to "songs"
private fun getSongsRecursively(
parent: MusicDirectory,
songs: MutableList<MusicDirectory.Entry>
) {
val service = MusicServiceFactory.getMusicService(context)
for (song in parent.getChildren(includeDirs = false, includeFiles = true)) {
if (!song.isVideo && !song.isDirectory) {
songs.add(song)
}
}
for ((id1, _, _, title) in parent.getChildren(true, includeFiles = false)) {
var root: MusicDirectory
if (allSongsId != id1) {
root = service.getMusicDirectory(id1, title, false, context)
getSongsRecursively(root, songs)
}
}
}
suspend fun getArtist(refresh: Boolean, id: String?, name: String?) {
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val service = MusicServiceFactory.getMusicService(context)
var root = MusicDirectory()
val musicDirectory = service.getArtist(id, name, refresh, context)
if (Util.getShouldShowAllSongsByArtist(context) &&
musicDirectory.findChild(allSongsId) == null &&
hasOnlyFolders(musicDirectory)
) {
val allSongs = MusicDirectory.Entry()
allSongs.isDirectory = true
allSongs.artist = name
allSongs.parent = id
allSongs.id = allSongsId
allSongs.title = String.format(
context.resources.getString(R.string.select_album_all_songs), name
)
root.addFirst(allSongs)
root.addAll(musicDirectory.getChildren())
} else {
root = musicDirectory
}
currentDirectory.postValue(root)
}
}
}
suspend fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?) {
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val service = MusicServiceFactory.getMusicService(context)
val musicDirectory: MusicDirectory
musicDirectory = if (allSongsId == id) {
val root = MusicDirectory()
val songs: MutableCollection<MusicDirectory.Entry> = LinkedList()
val artist = service.getArtist(parentId, "", false, context)
for ((id1) in artist.getChildren()) {
if (allSongsId != id1) {
val albumDirectory = service.getAlbum(
id1, "", false, context
)
for (song in albumDirectory.getChildren()) {
if (!song.isVideo) {
songs.add(song)
}
}
}
}
for (song in songs) {
if (!song.isDirectory) {
root.addChild(song)
}
}
root
} else {
service.getAlbum(id, name, refresh, context)
}
currentDirectory.postValue(musicDirectory)
}
}
}
suspend fun getSongsForGenre(genre: String, count: Int, offset: Int) {
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val service = MusicServiceFactory.getMusicService(context)
val musicDirectory = service.getSongsByGenre(genre, count, offset, context)
songsForGenre.postValue(musicDirectory)
}
}
}
suspend fun getStarred() {
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val service = MusicServiceFactory.getMusicService(context)
val musicDirectory: MusicDirectory
val context = context
if (Util.getShouldUseId3Tags(context)) {
musicDirectory = Util.getSongsFromSearchResult(service.getStarred2(context))
} else {
musicDirectory = Util.getSongsFromSearchResult(service.getStarred(context))
}
currentDirectory.postValue(musicDirectory)
}
}
}
suspend fun getVideos(refresh: Boolean) {
showHeader = false
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val service = MusicServiceFactory.getMusicService(context)
currentDirectory.postValue(service.getVideos(refresh, context))
}
}
}
suspend fun getRandom(size: Int) {
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val service = MusicServiceFactory.getMusicService(context)
val musicDirectory = service.getRandomSongs(size, context)
currentDirectoryIsSortable = false
currentDirectory.postValue(musicDirectory)
}
}
}
suspend fun getPlaylist(playlistId: String, playlistName: String?) {
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val service = MusicServiceFactory.getMusicService(context)
val musicDirectory = service.getPlaylist(playlistId, playlistName, context)
currentDirectory.postValue(musicDirectory)
}
}
}
suspend fun getPodcastEpisodes(podcastChannelId: String) {
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val service = MusicServiceFactory.getMusicService(context)
val musicDirectory = service.getPodcastEpisodes(podcastChannelId, context)
currentDirectory.postValue(musicDirectory)
}
}
}
suspend fun getShare(shareId: String) {
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val service = MusicServiceFactory.getMusicService(context)
val musicDirectory = MusicDirectory()
val shares = service.getShares(true, context)
for (share in shares) {
if (share.id == shareId) {
for (entry in share.getEntries()) {
musicDirectory.addChild(entry)
}
break
}
}
currentDirectory.postValue(musicDirectory)
}
}
}
suspend fun getAlbumList(albumListType: String, size: Int, offset: Int) {
showHeader = false
showSelectFolderHeader = !ActiveServerProvider.isOffline(context) &&
!Util.getShouldUseId3Tags(context) && (
(albumListType == AlbumListType.SORTED_BY_NAME.toString()) ||
(albumListType == AlbumListType.SORTED_BY_ARTIST.toString())
)
withContext(Dispatchers.IO) {
if (!ActiveServerProvider.isOffline(context)) {
val service = MusicServiceFactory.getMusicService(context)
val musicDirectory: MusicDirectory
val musicFolderId = if (showSelectFolderHeader) {
activeServerProvider.getActiveServer().musicFolderId
} else {
null
}
if (Util.getShouldUseId3Tags(context)) {
musicDirectory = service.getAlbumList2(
albumListType, size,
offset, musicFolderId, context
)
} else {
musicDirectory = service.getAlbumList(
albumListType, size,
offset, musicFolderId, context
)
}
currentDirectoryIsSortable = sortableCollection(albumListType)
albumList.postValue(musicDirectory)
}
}
}
private fun sortableCollection(albumListType: String): Boolean {
return albumListType != "newest" && albumListType != "random" &&
albumListType != "highest" && albumListType != "recent" &&
albumListType != "frequent"
}
// Returns true if the directory contains only folders
private fun hasOnlyFolders(musicDirectory: MusicDirectory) =
musicDirectory.getChildren(includeDirs = true, includeFiles = false).size ==
musicDirectory.getChildren(includeDirs = true, includeFiles = true).size
}

View File

@ -1,9 +1,9 @@
package org.moire.ultrasonic.fragment package org.moire.ultrasonic.fragment
import android.content.Context import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -22,8 +22,8 @@ import timber.log.Timber
class ServerSettingsModel( class ServerSettingsModel(
private val repository: ServerSettingDao, private val repository: ServerSettingDao,
private val activeServerProvider: ActiveServerProvider, private val activeServerProvider: ActiveServerProvider,
private val context: Context application: Application
) : ViewModel() { ) : AndroidViewModel(application) {
companion object { companion object {
private const val PREFERENCES_KEY_SERVER_MIGRATED = "serverMigrated" private const val PREFERENCES_KEY_SERVER_MIGRATED = "serverMigrated"
@ -54,6 +54,7 @@ class ServerSettingsModel(
if (rowCount == null || rowCount == 0) { if (rowCount == null || rowCount == 0) {
// First time load up the server settings from the Preferences // First time load up the server settings from the Preferences
val dbServerList = mutableListOf<ServerSetting>() val dbServerList = mutableListOf<ServerSetting>()
val context = getApplication<Application>().applicationContext
val settings = PreferenceManager.getDefaultSharedPreferences(context) val settings = PreferenceManager.getDefaultSharedPreferences(context)
val serverNum = settings.getInt(PREFERENCES_KEY_ACTIVE_SERVERS, 0) val serverNum = settings.getInt(PREFERENCES_KEY_ACTIVE_SERVERS, 0)

View File

@ -119,7 +119,6 @@ class LocalMediaPlayer(
}.start() }.start()
wakeLock.setReferenceCounted(false) wakeLock.setReferenceCounted(false)
Util.registerMediaButtonEventReceiver(context, true)
Timber.i("LocalMediaPlayer created") Timber.i("LocalMediaPlayer created")
} }
@ -146,7 +145,7 @@ class LocalMediaPlayer(
if (nextPlayingTask != null) { if (nextPlayingTask != null) {
nextPlayingTask!!.cancel() nextPlayingTask!!.cancel()
} }
Util.unregisterMediaButtonEventReceiver(context, true)
wakeLock.release() wakeLock.release()
} catch (exception: Throwable) { } catch (exception: Throwable) {
Timber.w(exception, "LocalMediaPlayer onDestroy exception: ") Timber.w(exception, "LocalMediaPlayer onDestroy exception: ")

View File

@ -12,6 +12,7 @@ import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.app.Service import android.app.Service
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Build import android.os.Build
@ -22,7 +23,6 @@ import android.support.v4.media.session.PlaybackStateCompat
import android.view.KeyEvent import android.view.KeyEvent
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import java.util.ArrayList
import org.koin.android.ext.android.inject import org.koin.android.ext.android.inject
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
import org.moire.ultrasonic.activity.NavigationActivity import org.moire.ultrasonic.activity.NavigationActivity
@ -33,6 +33,7 @@ import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X1
import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X2 import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X2
import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X3 import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X3
import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X4 import org.moire.ultrasonic.provider.UltrasonicAppWidgetProvider4X4
import org.moire.ultrasonic.receiver.MediaButtonIntentReceiver
import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.FileUtil import org.moire.ultrasonic.util.FileUtil
@ -792,7 +793,8 @@ class MediaPlayerService : Service() {
mediaSession = MediaSessionCompat(applicationContext, "UltrasonicService") mediaSession = MediaSessionCompat(applicationContext, "UltrasonicService")
mediaSessionToken = mediaSession!!.sessionToken mediaSessionToken = mediaSession!!.sessionToken
// mediaController = new MediaControllerCompat(getApplicationContext(), mediaSessionToken);
updateMediaButtonReceiver()
mediaSession!!.setCallback(object : MediaSessionCompat.Callback() { mediaSession!!.setCallback(object : MediaSessionCompat.Callback() {
override fun onPlay() { override fun onPlay() {
@ -838,10 +840,39 @@ class MediaPlayerService : Service() {
) )
} }
fun updateMediaButtonReceiver() {
if (Util.getMediaButtonsEnabled(applicationContext)) {
registerMediaButtonEventReceiver()
} else {
unregisterMediaButtonEventReceiver()
}
}
fun registerMediaButtonEventReceiver() {
val component = ComponentName(packageName, MediaButtonIntentReceiver::class.java.name)
val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON)
mediaButtonIntent.component = component
val pendingIntent = PendingIntent.getBroadcast(
this,
INTENT_CODE_MEDIA_BUTTON,
mediaButtonIntent,
PendingIntent.FLAG_CANCEL_CURRENT
)
mediaSession?.setMediaButtonReceiver(pendingIntent)
}
fun unregisterMediaButtonEventReceiver() {
mediaSession?.setMediaButtonReceiver(null)
}
companion object { companion object {
private const val NOTIFICATION_CHANNEL_ID = "org.moire.ultrasonic" private const val NOTIFICATION_CHANNEL_ID = "org.moire.ultrasonic"
private const val NOTIFICATION_CHANNEL_NAME = "Ultrasonic background service" private const val NOTIFICATION_CHANNEL_NAME = "Ultrasonic background service"
private const val NOTIFICATION_ID = 3033 private const val NOTIFICATION_ID = 3033
private const val INTENT_CODE_MEDIA_BUTTON = 161
private var instance: MediaPlayerService? = null private var instance: MediaPlayerService? = null
private val instanceLock = Any() private val instanceLock = Any()
@ -872,7 +903,7 @@ class MediaPlayerService : Service() {
@JvmStatic @JvmStatic
fun executeOnStartedMediaPlayerService( fun executeOnStartedMediaPlayerService(
context: Context, context: Context,
taskToExecute: Consumer<MediaPlayerService?> taskToExecute: (MediaPlayerService?) -> Unit
) { ) {
val t: Thread = object : Thread() { val t: Thread = object : Thread() {
@ -882,7 +913,7 @@ class MediaPlayerService : Service() {
Timber.e("ExecuteOnStarted.. failed to get a MediaPlayerService instance!") Timber.e("ExecuteOnStarted.. failed to get a MediaPlayerService instance!")
return return
} }
taskToExecute.accept(instance) taskToExecute(instance)
} }
} }
t.start() t.start()