Merge branch 'playback' into dev
This commit is contained in:
commit
f0bf7af7b4
5 changed files with 76 additions and 24 deletions
|
@ -43,24 +43,25 @@ class AuxioService : MediaLibraryService(), ForegroundListener {
|
|||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
handleIntent(intent)
|
||||
start(intent)
|
||||
return super.onBind(intent)
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
// TODO: Start command occurring from a foreign service basically implies a detached
|
||||
// service, we might need more handling here.
|
||||
handleIntent(intent)
|
||||
start(intent)
|
||||
return super.onStartCommand(intent, flags, startId)
|
||||
}
|
||||
|
||||
private fun handleIntent(intent: Intent?) {
|
||||
private fun start(intent: Intent?) {
|
||||
val nativeStart = intent?.getBooleanExtra(INTENT_KEY_NATIVE_START, false) ?: false
|
||||
if (!nativeStart) {
|
||||
// Some foreign code started us, no guarantees about foreground stability. Figure
|
||||
// out what to do.
|
||||
mediaSessionFragment.handleNonNativeStart()
|
||||
}
|
||||
indexingFragment.start()
|
||||
}
|
||||
|
||||
override fun onTaskRemoved(rootIntent: Intent?) {
|
||||
|
|
|
@ -280,9 +280,6 @@ constructor(
|
|||
}
|
||||
logD("Registering worker $worker")
|
||||
indexingWorker = worker
|
||||
if (indexingState == null) {
|
||||
worker.requestIndex(true)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
|
|
|
@ -21,13 +21,13 @@ package org.oxycblt.auxio.music.external
|
|||
import android.content.Context
|
||||
import android.net.Uri
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import javax.inject.Inject
|
||||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.music.fs.Components
|
||||
import org.oxycblt.auxio.music.fs.DocumentPathFactory
|
||||
import org.oxycblt.auxio.music.fs.Path
|
||||
import org.oxycblt.auxio.music.fs.contentResolverSafe
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Generic playlist file importing abstraction.
|
||||
|
@ -92,7 +92,20 @@ constructor(
|
|||
|
||||
return try {
|
||||
context.contentResolverSafe.openInputStream(uri)?.use {
|
||||
return m3u.read(it, filePath.directory)
|
||||
val imported = m3u.read(it, filePath.directory) ?: return null
|
||||
val name = imported.name
|
||||
if (name != null) {
|
||||
return imported
|
||||
}
|
||||
// Strip extension
|
||||
val fileName = filePath.name ?: return imported
|
||||
val split = fileName.split(".")
|
||||
var newName = split[0]
|
||||
// Replace delimiters with space
|
||||
newName = newName.replace(Regex("[_-]"), " ")
|
||||
// Replace long stretches of whitespace with one space
|
||||
newName = newName.replace(Regex("\\s+"), " ")
|
||||
return ImportedPlaylist(newName, imported.paths)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logE("Failed to import playlist: $e")
|
||||
|
|
|
@ -72,13 +72,19 @@ constructor(
|
|||
|
||||
fun release() {
|
||||
contentObserver.release()
|
||||
musicSettings.registerListener(this)
|
||||
musicRepository.addIndexingListener(this)
|
||||
musicRepository.addUpdateListener(this)
|
||||
musicRepository.unregisterWorker(this)
|
||||
musicRepository.removeIndexingListener(this)
|
||||
musicRepository.removeUpdateListener(this)
|
||||
musicSettings.unregisterListener(this)
|
||||
foregroundListener = null
|
||||
}
|
||||
|
||||
fun start() {
|
||||
if (musicRepository.indexingState == null) {
|
||||
requestIndex(true)
|
||||
}
|
||||
}
|
||||
|
||||
fun createNotification(post: (IndexerNotification?) -> Unit) {
|
||||
val state = musicRepository.indexingState
|
||||
if (state is IndexingState.Indexing) {
|
||||
|
|
|
@ -101,18 +101,52 @@ class WidgetProvider : AppWidgetProvider() {
|
|||
SizeF(180f, 272f) to newThinPaneLayout(context, uiSettings, state),
|
||||
SizeF(304f, 272f) to newWidePaneLayout(context, uiSettings, state))
|
||||
|
||||
// This is the order in which we will disable cover art layouts if they exceed the
|
||||
// maximum bitmap memory usage. (See the comment in the loop below for more info.)
|
||||
val victims =
|
||||
mutableSetOf(
|
||||
R.layout.widget_wafer_thin,
|
||||
R.layout.widget_wafer_wide,
|
||||
R.layout.widget_pane_thin,
|
||||
R.layout.widget_pane_wide,
|
||||
R.layout.widget_docked_thin,
|
||||
R.layout.widget_docked_wide,
|
||||
)
|
||||
|
||||
// Manually update AppWidgetManager with the new views.
|
||||
val awm = AppWidgetManager.getInstance(context)
|
||||
val component = ComponentName(context, this::class.java)
|
||||
while (victims.size > 0) {
|
||||
try {
|
||||
awm.updateAppWidgetCompat(context, component, views)
|
||||
logD("Successfully updated RemoteViews layout")
|
||||
return
|
||||
} catch (e: IllegalArgumentException) {
|
||||
val msg = e.message ?: return
|
||||
if (!msg.startsWith(
|
||||
"RemoteViews for widget update exceeds maximum bitmap memory usage")) {
|
||||
throw e
|
||||
}
|
||||
// Some android devices on Android 12-14 suffer from a bug where the maximum bitmap
|
||||
// size calculation does not factor in bitmaps shared across multiple RemoteView
|
||||
// forms.
|
||||
// To mitigate an outright crash, progressively disable layouts that contain cover
|
||||
// art
|
||||
// in order of least to most commonly used until it actually works.
|
||||
val victim = victims.first()
|
||||
val view = views.entries.find { it.value.layoutId == victim } ?: continue
|
||||
view.value.discardCover(context)
|
||||
victims.remove(victim)
|
||||
} catch (e: Exception) {
|
||||
// Layout update failed, gracefully degrade to the default widget.
|
||||
logW("Unable to update widget: $e")
|
||||
reset(context, uiSettings)
|
||||
}
|
||||
}
|
||||
// We flat-out cannot fit the bitmap into the widget. Weird.
|
||||
logW("Unable to update widget: Bitmap too large")
|
||||
reset(context, uiSettings)
|
||||
}
|
||||
|
||||
/**
|
||||
* Revert to the default layout that displays "No music playing".
|
||||
|
@ -288,16 +322,17 @@ class WidgetProvider : AppWidgetProvider() {
|
|||
context.getString(
|
||||
R.string.desc_album_cover, state.song.album.name.resolve(context)))
|
||||
} else {
|
||||
// We are unable to use the typical placeholder cover with the song item due to
|
||||
// limitations with the corner radius. Instead use a custom-made album icon as the
|
||||
// placeholder.
|
||||
setImageViewResource(R.id.widget_cover, R.drawable.ic_remote_default_cover_24)
|
||||
setContentDescription(R.id.widget_cover, context.getString(R.string.desc_no_cover))
|
||||
discardCover(context)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
private fun RemoteViews.discardCover(context: Context) {
|
||||
setImageViewResource(R.id.widget_cover, R.drawable.ic_remote_default_cover_24)
|
||||
setContentDescription(R.id.widget_cover, context.getString(R.string.desc_no_cover))
|
||||
}
|
||||
|
||||
private fun RemoteViews.setupFillingCover(uiSettings: UISettings): RemoteViews {
|
||||
// Below API 31, enable a rounded background only if round mode is enabled.
|
||||
// On API 31+, the background should always be round in order to fit in with other
|
||||
|
|
Loading…
Reference in a new issue