From be9eec625ab191a3e7bf99a94457bfa62575659e Mon Sep 17 00:00:00 2001 From: pca006132 Date: Mon, 3 Nov 2025 14:46:10 +0800 Subject: [PATCH] avoid full updates --- .../tempo/service/MediaService.kt | 89 ++++++++++++++----- .../tempo/widget/WidgetUpdateManager.java | 82 +++++++++-------- .../tempo/widget/WidgetViewsFactory.java | 2 +- 3 files changed, 108 insertions(+), 65 deletions(-) diff --git a/app/src/degoogled/java/com/cappielloantonio/tempo/service/MediaService.kt b/app/src/degoogled/java/com/cappielloantonio/tempo/service/MediaService.kt index f1ae6de7..b7ea7773 100644 --- a/app/src/degoogled/java/com/cappielloantonio/tempo/service/MediaService.kt +++ b/app/src/degoogled/java/com/cappielloantonio/tempo/service/MediaService.kt @@ -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.empty>() + + 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,7 +425,8 @@ class MediaService : MediaLibraryService() { } else { stopWidgetUpdates() } - updateWidget() + if (screenOn) + updateWidget() } override fun onPlaybackStateChanged(playbackState: Int) { @@ -505,11 +541,11 @@ class MediaService : MediaLibraryService() { private inner class CustomGlideTarget : CustomTarget() { override fun onResourceReady(resource: Bitmap, transition: Transition?) { - 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,21 +576,30 @@ class MediaService : MediaLibraryService() { CustomGlideTarget()) } - WidgetUpdateManager.updateFromState( - this, - title ?: "", - artist ?: "", - album ?: "", - artCache, - player.isPlaying, - player.shuffleModeEnabled, - player.repeatMode, - position, - duration, - songLink, - albumLink, - artistLink - ) + val newPlayerState = Triple(player.isPlaying, player.shuffleModeEnabled, player.repeatMode) + if (nowPlayingChanged || prevPlayerStates != newPlayerState) { + WidgetUpdateManager.updateFromState( + this, + title ?: "", + artist ?: "", + album ?: "", + Optional.ofNullable(artCache), + player.isPlaying, + player.shuffleModeEnabled, + player.repeatMode, + position, + duration, + songLink, + albumLink, + artistLink + ) + prevPlayerStates = newPlayerState + Log.d("MediaService", "fullUpdate"); + } else { + WidgetUpdateManager.updateProgress(this, position, duration) + Log.d("MediaService", "updateProgress"); + } + nowPlayingChanged = false } private fun scheduleWidgetUpdates() { diff --git a/app/src/main/java/com/cappielloantonio/tempo/widget/WidgetUpdateManager.java b/app/src/main/java/com/cappielloantonio/tempo/widget/WidgetUpdateManager.java index 6bf52f95..c4ade7c1 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/widget/WidgetUpdateManager.java +++ b/app/src/main/java/com/cappielloantonio/tempo/widget/WidgetUpdateManager.java @@ -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 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> 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() { @Override public void onResourceReady(Bitmap resource, Transition 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); } } diff --git a/app/src/main/java/com/cappielloantonio/tempo/widget/WidgetViewsFactory.java b/app/src/main/java/com/cappielloantonio/tempo/widget/WidgetViewsFactory.java index c66fd1cb..3cc53dc8 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/widget/WidgetViewsFactory.java +++ b/app/src/main/java/com/cappielloantonio/tempo/widget/WidgetViewsFactory.java @@ -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() {