avoid full updates

This commit is contained in:
pca006132 2025-11-03 14:46:10 +08:00
parent b335ddec01
commit be9eec625a
3 changed files with 108 additions and 65 deletions

View file

@ -4,7 +4,10 @@ import android.annotation.SuppressLint
import android.app.PendingIntent.FLAG_IMMUTABLE
import android.app.PendingIntent.FLAG_UPDATE_CURRENT
import android.app.TaskStackBuilder
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.net.ConnectivityManager
@ -60,7 +63,7 @@ class MediaService : MediaLibraryService() {
private var widgetUpdateScheduled = false
private val widgetUpdateRunnable = object : Runnable {
override fun run() {
if (!player.isPlaying) {
if (!player.isPlaying || !screenOn) {
widgetUpdateScheduled = false
return
}
@ -68,7 +71,29 @@ class MediaService : MediaLibraryService() {
widgetUpdateHandler.postDelayed(this, WIDGET_UPDATE_INTERVAL_MS)
}
}
@Volatile private var artCache : Optional<Optional<Bitmap>> = Optional.empty<Optional<Bitmap>>()
private var prevPlayerStates = Triple(false, false, -1)
@Volatile private var nowPlayingChanged = false
@Volatile private var artCacheUpdated = false
@Volatile private var artCache : Bitmap? = null
@Volatile private var screenOn = true
val broadCastReceiver = object : BroadcastReceiver() {
override fun onReceive(contxt: Context?, intent: Intent?) {
when (intent?.action) {
Intent.ACTION_SCREEN_ON -> {
Log.d("MediaService", "screenOn");
screenOn = true
widgetUpdateHandler.post(widgetUpdateRunnable)
}
Intent.ACTION_SCREEN_OFF -> {
Log.d("MediaService", "screenOff");
screenOn = false
}
}
}
}
inner class LocalBinder : Binder() {
fun getEqualizerManager(): EqualizerManager {
@ -134,6 +159,7 @@ class MediaService : MediaLibraryService() {
initializePlayerListener()
initializeEqualizerManager()
initializeNetworkListener()
initializeScreenListener()
setPlayer(player)
}
@ -143,6 +169,7 @@ class MediaService : MediaLibraryService() {
}
override fun onDestroy() {
unregisterReceiver(broadCastReceiver)
releaseNetworkCallback()
equalizerManager.release()
stopWidgetUpdates()
@ -288,6 +315,12 @@ class MediaService : MediaLibraryService() {
player.repeatMode = Preferences.getRepeatMode()
}
private fun initializeScreenListener() {
val filter = IntentFilter(Intent.ACTION_SCREEN_ON)
filter.addAction(Intent.ACTION_SCREEN_OFF)
registerReceiver(broadCastReceiver, filter)
}
private fun initializeEqualizerManager() {
equalizerManager = EqualizerManager()
val audioSessionId = player.audioSessionId
@ -376,7 +409,9 @@ class MediaService : MediaLibraryService() {
}
override fun onIsPlayingChanged(isPlaying: Boolean) {
artCache = Optional.empty()
nowPlayingChanged = true
artCacheUpdated = false
artCache = null
if (!isPlaying) {
MediaManager.setPlayingPausedTimestamp(
player.currentMediaItem,
@ -390,6 +425,7 @@ class MediaService : MediaLibraryService() {
} else {
stopWidgetUpdates()
}
if (screenOn)
updateWidget()
}
@ -505,11 +541,11 @@ class MediaService : MediaLibraryService() {
private inner class CustomGlideTarget : CustomTarget<Bitmap>() {
override fun onResourceReady(resource: Bitmap, transition: Transition<in Bitmap>?) {
artCache = Optional.of(Optional.of(resource))
artCache = resource
}
override fun onLoadCleared(placeholder: Drawable?) {
artCache = Optional.of(Optional.empty())
artCache = null
}
}
@ -532,7 +568,7 @@ class MediaService : MediaLibraryService() {
val position = player.currentPosition.takeIf { it != C.TIME_UNSET } ?: 0L
val duration = player.duration.takeIf { it != C.TIME_UNSET } ?: 0L
if (!TextUtils.isEmpty(coverId) && artCache.isEmpty) {
if (!TextUtils.isEmpty(coverId) && nowPlayingChanged) {
CustomGlideRequest.loadAlbumArtBitmap(
applicationContext,
coverId,
@ -540,12 +576,14 @@ class MediaService : MediaLibraryService() {
CustomGlideTarget())
}
val newPlayerState = Triple(player.isPlaying, player.shuffleModeEnabled, player.repeatMode)
if (nowPlayingChanged || prevPlayerStates != newPlayerState) {
WidgetUpdateManager.updateFromState(
this,
title ?: "",
artist ?: "",
album ?: "",
artCache,
Optional.ofNullable(artCache),
player.isPlaying,
player.shuffleModeEnabled,
player.repeatMode,
@ -555,6 +593,13 @@ class MediaService : MediaLibraryService() {
albumLink,
artistLink
)
prevPlayerStates = newPlayerState
Log.d("MediaService", "fullUpdate");
} else {
WidgetUpdateManager.updateProgress(this, position, duration)
Log.d("MediaService", "updateProgress");
}
nowPlayingChanged = false
}
private fun scheduleWidgetUpdates() {

View file

@ -7,6 +7,7 @@ import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.RemoteViews;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
@ -36,7 +37,7 @@ public final class WidgetUpdateManager {
String title,
String artist,
String album,
Bitmap art,
Optional<Bitmap> art,
boolean playing,
boolean shuffleEnabled,
int repeatMode,
@ -54,13 +55,47 @@ public final class WidgetUpdateManager {
AppWidgetManager mgr = AppWidgetManager.getInstance(ctx);
int[] ids = mgr.getAppWidgetIds(new ComponentName(ctx, WidgetProvider4x1.class));
for (int id : ids) {
android.widget.RemoteViews rv = choosePopulate(ctx, title, artist, album, art, playing,
android.widget.RemoteViews rv = choosePopulate(ctx, title, artist, album, art.orElse(null), playing,
timing.elapsedText, timing.totalText, timing.progress, shuffleEnabled, repeatMode, id);
WidgetProvider.attachIntents(ctx, rv, id, songLink, albumLink, artistLink);
mgr.updateAppWidget(id, rv);
}
}
public static void updateProgress(Context ctx,
long positionMs,
long durationMs) {
final TimingInfo timing = createTimingInfo(positionMs, durationMs);
AppWidgetManager mgr = AppWidgetManager.getInstance(ctx);
int[] ids = mgr.getAppWidgetIds(new ComponentName(ctx, WidgetProvider4x1.class));
for (int id : ids) {
LayoutSize size = resolveLayoutSize(ctx, id);
int layoutRes = 0;
switch (size) {
case MEDIUM:
layoutRes = R.layout.widget_layout_medium;
break;
case LARGE:
layoutRes = R.layout.widget_layout_large_short;
break;
case EXPANDED:
layoutRes = R.layout.widget_layout_large;
break;
case COMPACT:
default:
layoutRes = R.layout.widget_layout_compact;
break;
}
RemoteViews rv = new RemoteViews(ctx.getPackageName(), layoutRes);
int safeProgress = Math.max(0, Math.min(timing.progress, WidgetViewsFactory.PROGRESS_MAX));
rv.setTextViewText(R.id.time_elapsed, timing.elapsedText);
rv.setTextViewText(R.id.time_total, timing.totalText);
rv.setProgressBar(R.id.progress, WidgetViewsFactory.PROGRESS_MAX, safeProgress, false);
mgr.updateAppWidget(id, rv);
}
}
public static void pushNow(Context ctx) {
AppWidgetManager mgr = AppWidgetManager.getInstance(ctx);
int[] ids = mgr.getAppWidgetIds(new ComponentName(ctx, WidgetProvider4x1.class));
@ -72,43 +107,6 @@ public final class WidgetUpdateManager {
}
public static void updateFromState(Context ctx,
String title,
String artist,
String album,
Optional<Optional<Bitmap>> coverArt,
boolean playing,
boolean shuffleEnabled,
int repeatMode,
long positionMs,
long durationMs,
String songLink,
String albumLink,
String artistLink) {
final Context appCtx = ctx.getApplicationContext();
final String t = TextUtils.isEmpty(title) ? appCtx.getString(R.string.widget_not_playing) : title;
final String a = TextUtils.isEmpty(artist) ? appCtx.getString(R.string.widget_placeholder_subtitle) : artist;
final String alb = !TextUtils.isEmpty(album) ? album : "";
final boolean p = playing;
final boolean sh = shuffleEnabled;
final int rep = repeatMode;
final TimingInfo timing = createTimingInfo(positionMs, durationMs);
final String songLinkFinal = songLink;
final String albumLinkFinal = albumLink;
final String artistLinkFinal = artistLink;
AppWidgetManager mgr = AppWidgetManager.getInstance(appCtx);
int[] ids = mgr.getAppWidgetIds(new ComponentName(appCtx, WidgetProvider4x1.class));
Bitmap resource = coverArt.filter(Optional::isPresent).map(Optional::get).orElse(null);
for (int id : ids) {
android.widget.RemoteViews rv = choosePopulate(appCtx, t, a, alb, resource, p,
timing.elapsedText, timing.totalText, timing.progress, sh, rep, id);
WidgetProvider.attachIntents(appCtx, rv, id, songLinkFinal, albumLinkFinal, artistLinkFinal);
mgr.updateAppWidget(id, rv);
}
}
public static void updateFromState(Context ctx,
String title,
String artist,
@ -131,19 +129,19 @@ public final class WidgetUpdateManager {
new CustomTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, Transition<? super Bitmap> transition) {
updateFromState(ctx, title, artist, album, Optional.of(Optional.of(resource)),
updateFromState(ctx, title, artist, album, Optional.of(resource),
playing, shuffleEnabled, repeatMode, positionMs, durationMs, songLink, albumLink, artistLink);
}
@Override
public void onLoadCleared(Drawable placeholder) {
updateFromState(ctx, title, artist, album, Optional.of(Optional.empty()),
updateFromState(ctx, title, artist, album, Optional.empty(),
playing, shuffleEnabled, repeatMode, positionMs, durationMs, songLink, albumLink, artistLink);
}
}
);
} else {
updateFromState(ctx, title, artist, album, Optional.of(Optional.empty()),
updateFromState(ctx, title, artist, album, Optional.empty(),
playing, shuffleEnabled, repeatMode, positionMs, durationMs, songLink, albumLink, artistLink);
}
}

View file

@ -19,7 +19,7 @@ import com.cappielloantonio.tempo.R;
public final class WidgetViewsFactory {
static final int PROGRESS_MAX = 1000;
public static final int PROGRESS_MAX = 1000;
private static final float ALBUM_ART_CORNER_RADIUS_DP = 6f;
private WidgetViewsFactory() {