mirror of
https://github.com/KDE/kdeconnect-android
synced 2025-08-22 18:07:55 +00:00
Offer to "continue playing" media on this device after pausing
Based on the MR !249 Co-authored-by: Alex Gravenor <blazingkin@gmail.com>
This commit is contained in:
parent
411bcc3960
commit
3d166e6d4b
@ -569,4 +569,11 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
|
|||||||
<string name="findmyphone_notifications_explanation">The notifications permission is needed so the phone can ring when the app is in the background</string>
|
<string name="findmyphone_notifications_explanation">The notifications permission is needed so the phone can ring when the app is in the background</string>
|
||||||
<string name="no_notifications">Notifications are disabled, you won\'t receive incoming pair notifications.</string>
|
<string name="no_notifications">Notifications are disabled, you won\'t receive incoming pair notifications.</string>
|
||||||
|
|
||||||
|
|
||||||
|
<string name="mpris_keepwatching">Continue playing</string>
|
||||||
|
<string name="mpris_keepwatching_key" translatable="false">mpris_keepwatching_enabled</string>
|
||||||
|
<string name="mpris_keepwatching_settings_title">Continue playing</string>
|
||||||
|
<string name="mpris_keepwatching_settings_summary">Show a silent notification to continue playing on this device after closing media</string>
|
||||||
|
<string name="notification_channel_keepwatching">Continue playing</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -28,4 +28,11 @@ SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted
|
|||||||
android:summary="@string/mpris_notification_settings_summary"
|
android:summary="@string/mpris_notification_settings_summary"
|
||||||
android:title="@string/mpris_notification_settings_title" />
|
android:title="@string/mpris_notification_settings_title" />
|
||||||
|
|
||||||
|
<SwitchPreference
|
||||||
|
android:id="@+id/mpris_keepwatching_preference"
|
||||||
|
android:defaultValue="true"
|
||||||
|
android:key="@string/mpris_keepwatching_key"
|
||||||
|
android:summary="@string/mpris_keepwatching_settings_summary"
|
||||||
|
android:title="@string/mpris_keepwatching_settings_title" />
|
||||||
|
|
||||||
</PreferenceScreen>
|
</PreferenceScreen>
|
||||||
|
@ -35,6 +35,8 @@ public class NotificationHelper {
|
|||||||
|
|
||||||
public final static String RECEIVENOTIFICATION = "receive";
|
public final static String RECEIVENOTIFICATION = "receive";
|
||||||
public final static String HIGHPRIORITY = "highpriority";
|
public final static String HIGHPRIORITY = "highpriority";
|
||||||
|
public final static String CONTINUEWATCHING = "continuewatching";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void notifyCompat(NotificationManager notificationManager, int notificationId, Notification notification) {
|
public static void notifyCompat(NotificationManager notificationManager, int notificationId, Notification notification) {
|
||||||
@ -87,14 +89,23 @@ public class NotificationHelper {
|
|||||||
.Builder(Channels.RECEIVENOTIFICATION, NotificationManagerCompat.IMPORTANCE_DEFAULT)
|
.Builder(Channels.RECEIVENOTIFICATION, NotificationManagerCompat.IMPORTANCE_DEFAULT)
|
||||||
.setName(context.getString(R.string.notification_channel_receivenotification))
|
.setName(context.getString(R.string.notification_channel_receivenotification))
|
||||||
.build();
|
.build();
|
||||||
final NotificationChannelCompat highPriorityChannel = new NotificationChannelCompat
|
final NotificationChannelCompat continueWatchingChannel = new NotificationChannelCompat
|
||||||
.Builder(Channels.HIGHPRIORITY, NotificationManagerCompat.IMPORTANCE_HIGH)
|
.Builder(Channels.HIGHPRIORITY, NotificationManagerCompat.IMPORTANCE_HIGH)
|
||||||
.setName(context.getString(R.string.notification_channel_high_priority))
|
.setName(context.getString(R.string.notification_channel_high_priority))
|
||||||
.build();
|
.build();
|
||||||
|
/* This notification should be highly visible *only* if the user looks at their phone */
|
||||||
|
/* It should not be a distraction. It should be a convenient button to press */
|
||||||
|
final NotificationChannelCompat highPriorityChannel = new NotificationChannelCompat
|
||||||
|
.Builder(Channels.CONTINUEWATCHING, NotificationManagerCompat.IMPORTANCE_HIGH)
|
||||||
|
.setName(context.getString(R.string.notification_channel_keepwatching))
|
||||||
|
.setVibrationEnabled(false)
|
||||||
|
.setLightsEnabled(false)
|
||||||
|
.setSound(null, null)
|
||||||
|
.build();
|
||||||
final List<NotificationChannelCompat> channels = Arrays.asList(persistentChannel,
|
final List<NotificationChannelCompat> channels = Arrays.asList(persistentChannel,
|
||||||
defaultChannel, mediaChannel, fileTransferDownloadChannel, fileTransferUploadChannel,
|
defaultChannel, mediaChannel, fileTransferDownloadChannel, fileTransferUploadChannel,
|
||||||
fileTransferErrorChannel, receiveNotificationChannel, highPriorityChannel);
|
fileTransferErrorChannel, receiveNotificationChannel, highPriorityChannel,
|
||||||
|
continueWatchingChannel);
|
||||||
|
|
||||||
NotificationManagerCompat.from(context).createNotificationChannelsCompat(channels);
|
NotificationManagerCompat.from(context).createNotificationChannelsCompat(channels);
|
||||||
|
|
||||||
@ -102,7 +113,7 @@ public class NotificationHelper {
|
|||||||
// Use this to deprecate old channels.
|
// Use this to deprecate old channels.
|
||||||
NotificationManagerCompat.from(context).deleteUnlistedNotificationChannels(
|
NotificationManagerCompat.from(context).deleteUnlistedNotificationChannels(
|
||||||
channels.stream()
|
channels.stream()
|
||||||
.map(notificationChannelCompat -> notificationChannelCompat.getId())
|
.map(NotificationChannelCompat::getId)
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,12 +7,20 @@ package org.kde.kdeconnect.Plugins.MprisPlugin
|
|||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import org.kde.kdeconnect.Helpers.NotificationHelper
|
||||||
|
import org.kde.kdeconnect.Helpers.VideoUrlsHelper
|
||||||
import org.kde.kdeconnect.NetworkPacket
|
import org.kde.kdeconnect.NetworkPacket
|
||||||
import org.kde.kdeconnect.Plugins.MprisPlugin.AlbumArtCache.deregisterPlugin
|
import org.kde.kdeconnect.Plugins.MprisPlugin.AlbumArtCache.deregisterPlugin
|
||||||
import org.kde.kdeconnect.Plugins.MprisPlugin.AlbumArtCache.getAlbumArt
|
import org.kde.kdeconnect.Plugins.MprisPlugin.AlbumArtCache.getAlbumArt
|
||||||
@ -243,6 +251,7 @@ class MprisPlugin : Plugin() {
|
|||||||
if (np.has("player")) {
|
if (np.has("player")) {
|
||||||
val playerStatus = players[np.getString("player")]
|
val playerStatus = players[np.getString("player")]
|
||||||
if (playerStatus != null) {
|
if (playerStatus != null) {
|
||||||
|
val wasPlaying = playerStatus.isPlaying
|
||||||
//Note: title, artist and album will not be available for all desktop clients
|
//Note: title, artist and album will not be available for all desktop clients
|
||||||
playerStatus.title = np.getString("title", playerStatus.title)
|
playerStatus.title = np.getString("title", playerStatus.title)
|
||||||
playerStatus.artist = np.getString("artist", playerStatus.artist)
|
playerStatus.artist = np.getString("artist", playerStatus.artist)
|
||||||
@ -286,6 +295,11 @@ class MprisPlugin : Plugin() {
|
|||||||
playerStatusUpdated.remove(key)
|
playerStatusUpdated.remove(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check to see if a stream has stopped playing and we should deliver a notification
|
||||||
|
if (np.has("isPlaying") && !playerStatus.isPlaying && wasPlaying) {
|
||||||
|
showContinueWatchingNotification(playerStatus)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,8 +323,13 @@ class MprisPlugin : Plugin() {
|
|||||||
val oldPlayer = it.key
|
val oldPlayer = it.key
|
||||||
val found = newPlayerList.stream().anyMatch { newPlayer -> newPlayer == oldPlayer }
|
val found = newPlayerList.stream().anyMatch { newPlayer -> newPlayer == oldPlayer }
|
||||||
if (!found) {
|
if (!found) {
|
||||||
iter.remove()
|
// Player got removed
|
||||||
equals = false
|
equals = false
|
||||||
|
iter.remove()
|
||||||
|
val playerStatus = it.value
|
||||||
|
if (playerStatus.isPlaying) {
|
||||||
|
showContinueWatchingNotification(playerStatus)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!equals) {
|
if (!equals) {
|
||||||
@ -328,6 +347,34 @@ class MprisPlugin : Plugin() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showContinueWatchingNotification(playerStatus: MprisPlayer) {
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
if (prefs.getBoolean(context.getString(R.string.mpris_keepwatching_key), true) &&
|
||||||
|
(playerStatus.url.startsWith("http://") || playerStatus.url.startsWith("https://"))
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
val url = VideoUrlsHelper.formatUriWithSeek(playerStatus.url, playerStatus.position).toString()
|
||||||
|
val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
|
||||||
|
val pendingIntent = PendingIntent.getActivity(device.context, 0, browserIntent, PendingIntent.FLAG_IMMUTABLE)
|
||||||
|
|
||||||
|
val notificationManager = ContextCompat.getSystemService(device.context, NotificationManager::class.java)
|
||||||
|
val builder = NotificationCompat.Builder(device.context, NotificationHelper.Channels.CONTINUEWATCHING)
|
||||||
|
.setContentTitle(context.resources.getString(R.string.kde_connect))
|
||||||
|
.setSmallIcon(R.drawable.ic_play_white)
|
||||||
|
.setTimeoutAfter(3000)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setContentText(context.resources.getString(R.string.mpris_keepwatching) + " " + playerStatus.title)
|
||||||
|
NotificationHelper.notifyCompat(
|
||||||
|
notificationManager,
|
||||||
|
System.currentTimeMillis().toInt(),
|
||||||
|
builder.build()
|
||||||
|
)
|
||||||
|
} catch (e: MalformedURLException) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override val supportedPacketTypes: Array<String> = arrayOf(PACKET_TYPE_MPRIS)
|
override val supportedPacketTypes: Array<String> = arrayOf(PACKET_TYPE_MPRIS)
|
||||||
|
|
||||||
override val outgoingPacketTypes: Array<String> = arrayOf(PACKET_TYPE_MPRIS_REQUEST)
|
override val outgoingPacketTypes: Array<String> = arrayOf(PACKET_TYPE_MPRIS_REQUEST)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user