mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 07:13:00 +00:00 
			
		
		
		
	Create individual stream notifications for convenience on Android 7.0 and later.
This commit is contained in:
		 Isira Seneviratne
					Isira Seneviratne
				
			
				
					committed by
					
						 TobiGr
						TobiGr
					
				
			
			
				
	
			
			
			 TobiGr
						TobiGr
					
				
			
						parent
						
							8cfba4003d
						
					
				
				
					commit
					7742c40ac0
				
			| @@ -1,6 +1,8 @@ | |||||||
| package org.schabi.newpipe.local.feed.notifications | package org.schabi.newpipe.local.feed.notifications | ||||||
|  |  | ||||||
|  | import android.app.Notification | ||||||
| import android.app.NotificationManager | 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 | ||||||
| @@ -12,6 +14,7 @@ import androidx.core.app.NotificationCompat | |||||||
| import androidx.core.app.NotificationManagerCompat | import androidx.core.app.NotificationManagerCompat | ||||||
| import androidx.core.app.PendingIntentCompat | import androidx.core.app.PendingIntentCompat | ||||||
| import androidx.core.content.ContextCompat | import androidx.core.content.ContextCompat | ||||||
|  | import androidx.core.content.getSystemService | ||||||
| import androidx.preference.PreferenceManager | import androidx.preference.PreferenceManager | ||||||
| import com.squareup.picasso.Picasso | import com.squareup.picasso.Picasso | ||||||
| import com.squareup.picasso.Target | import com.squareup.picasso.Target | ||||||
| @@ -26,23 +29,22 @@ import org.schabi.newpipe.util.PicassoHelper | |||||||
|  * Helper for everything related to show notifications about new streams to the user. |  * Helper for everything related to show notifications about new streams to the user. | ||||||
|  */ |  */ | ||||||
| class NotificationHelper(val context: Context) { | class NotificationHelper(val context: Context) { | ||||||
|  |     private val manager = context.getSystemService<NotificationManager>()!! | ||||||
|     private val manager = context.getSystemService( |  | ||||||
|         Context.NOTIFICATION_SERVICE |  | ||||||
|     ) as NotificationManager |  | ||||||
|  |  | ||||||
|     private val iconLoadingTargets = ArrayList<Target>() |     private val iconLoadingTargets = ArrayList<Target>() | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Show a notification about new streams from a single channel. |      * Show notifications for new streams from a single channel. The individual notifications are | ||||||
|      * Opening the notification will open the corresponding channel page. |      * expandable on Android 7.0 and later. | ||||||
|  |      * | ||||||
|  |      * Opening the summary notification will open the corresponding channel page. Opening the | ||||||
|  |      * individual notifications will open the corresponding video. | ||||||
|      */ |      */ | ||||||
|     fun displayNewStreamsNotification(data: FeedUpdateInfo) { |     fun displayNewStreamsNotifications(data: FeedUpdateInfo) { | ||||||
|         val newStreams: List<StreamInfoItem> = data.newStreams |         val newStreams = data.newStreams | ||||||
|         val summary = context.resources.getQuantityString( |         val summary = context.resources.getQuantityString( | ||||||
|             R.plurals.new_streams, newStreams.size, newStreams.size |             R.plurals.new_streams, newStreams.size, newStreams.size | ||||||
|         ) |         ) | ||||||
|         val builder = NotificationCompat.Builder( |         val summaryBuilder = NotificationCompat.Builder( | ||||||
|             context, |             context, | ||||||
|             context.getString(R.string.streams_notification_channel_id) |             context.getString(R.string.streams_notification_channel_id) | ||||||
|         ) |         ) | ||||||
| @@ -50,7 +52,7 @@ class NotificationHelper(val context: Context) { | |||||||
|             .setContentText( |             .setContentText( | ||||||
|                 data.listInfo.relatedItems.joinToString( |                 data.listInfo.relatedItems.joinToString( | ||||||
|                     context.getString(R.string.enumeration_comma) |                     context.getString(R.string.enumeration_comma) | ||||||
|                 ) { x -> x.name } |                 ) { it.name } | ||||||
|             ) |             ) | ||||||
|             .setNumber(newStreams.size) |             .setNumber(newStreams.size) | ||||||
|             .setBadgeIconType(NotificationCompat.BADGE_ICON_LARGE) |             .setBadgeIconType(NotificationCompat.BADGE_ICON_LARGE) | ||||||
| @@ -60,16 +62,19 @@ class NotificationHelper(val context: Context) { | |||||||
|             .setColorized(true) |             .setColorized(true) | ||||||
|             .setAutoCancel(true) |             .setAutoCancel(true) | ||||||
|             .setCategory(NotificationCompat.CATEGORY_SOCIAL) |             .setCategory(NotificationCompat.CATEGORY_SOCIAL) | ||||||
|  |             .setGroupSummary(true) | ||||||
|  |             .setGroup(data.listInfo.url) | ||||||
|  |             .setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY) | ||||||
|  |  | ||||||
|         // Build style |         // Build a summary notification for Android versions < 7.0 | ||||||
|         val style = NotificationCompat.InboxStyle() |         val style = NotificationCompat.InboxStyle() | ||||||
|  |             .setSummaryText(summary) | ||||||
|  |             .setBigContentTitle(data.name) | ||||||
|         newStreams.forEach { style.addLine(it.name) } |         newStreams.forEach { style.addLine(it.name) } | ||||||
|         style.setSummaryText(summary) |         summaryBuilder.setStyle(style) | ||||||
|         style.setBigContentTitle(data.name) |  | ||||||
|         builder.setStyle(style) |  | ||||||
|  |  | ||||||
|         // open the channel page when clicking on the notification |         // open the channel page when clicking on the summary notification | ||||||
|         builder.setContentIntent( |         summaryBuilder.setContentIntent( | ||||||
|             PendingIntentCompat.getActivity( |             PendingIntentCompat.getActivity( | ||||||
|                 context, |                 context, | ||||||
|                 data.pseudoId, |                 data.pseudoId, | ||||||
| @@ -84,13 +89,21 @@ class NotificationHelper(val context: Context) { | |||||||
|         // a Target is like a listener for image loading events |         // a Target is like a listener for image loading events | ||||||
|         val target = object : Target { |         val target = object : Target { | ||||||
|             override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) { |             override fun onBitmapLoaded(bitmap: Bitmap, from: Picasso.LoadedFrom) { | ||||||
|                 builder.setLargeIcon(bitmap) // set only if there is actually one |                 summaryBuilder.setLargeIcon(bitmap) // set only if there is actually one | ||||||
|                 manager.notify(data.pseudoId, builder.build()) |  | ||||||
|  |                 // Show individual stream notifications | ||||||
|  |                 showStreamNotifications(newStreams, data.listInfo.serviceId) | ||||||
|  |                 // Show summary notification | ||||||
|  |                 manager.notify(data.pseudoId, summaryBuilder.build()) | ||||||
|  |  | ||||||
|                 iconLoadingTargets.remove(this) // allow it to be garbage-collected |                 iconLoadingTargets.remove(this) // allow it to be garbage-collected | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             override fun onBitmapFailed(e: Exception, errorDrawable: Drawable) { |             override fun onBitmapFailed(e: Exception, errorDrawable: Drawable) { | ||||||
|                 manager.notify(data.pseudoId, builder.build()) |                 // Show individual stream notifications | ||||||
|  |                 showStreamNotifications(newStreams, data.listInfo.serviceId) | ||||||
|  |                 // Show summary notification | ||||||
|  |                 manager.notify(data.pseudoId, summaryBuilder.build()) | ||||||
|                 iconLoadingTargets.remove(this) // allow it to be garbage-collected |                 iconLoadingTargets.remove(this) // allow it to be garbage-collected | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -106,6 +119,41 @@ class NotificationHelper(val context: Context) { | |||||||
|         PicassoHelper.loadNotificationIcon(data.avatarUrl).into(target) |         PicassoHelper.loadNotificationIcon(data.avatarUrl).into(target) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private fun showStreamNotifications(newStreams: List<StreamInfoItem>, serviceId: Int) { | ||||||
|  |         newStreams.asSequence() | ||||||
|  |             .map { it to createStreamNotification(it, serviceId) } | ||||||
|  |             .forEach { (stream, notification) -> | ||||||
|  |                 manager.notify(stream.url.hashCode(), notification) | ||||||
|  |             } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun createStreamNotification(item: StreamInfoItem, serviceId: Int): Notification { | ||||||
|  |         return NotificationCompat.Builder( | ||||||
|  |             context, | ||||||
|  |             context.getString(R.string.streams_notification_channel_id) | ||||||
|  |         ) | ||||||
|  |             .setSmallIcon(R.drawable.ic_newpipe_triangle_white) | ||||||
|  |             .setContentTitle(item.name) | ||||||
|  |             .setContentText(item.uploaderName) | ||||||
|  |             .setGroup(item.uploaderUrl) | ||||||
|  |             .setColor(ContextCompat.getColor(context, R.color.ic_launcher_background)) | ||||||
|  |             .setColorized(true) | ||||||
|  |             .setAutoCancel(true) | ||||||
|  |             .setCategory(NotificationCompat.CATEGORY_SOCIAL) | ||||||
|  |             .setContentIntent( | ||||||
|  |                 // Open the stream link in the player when clicking on the notification. | ||||||
|  |                 PendingIntentCompat.getActivity( | ||||||
|  |                     context, | ||||||
|  |                     item.url.hashCode(), | ||||||
|  |                     NavigationHelper.getStreamIntent(context, serviceId, item.url, item.name), | ||||||
|  |                     PendingIntent.FLAG_UPDATE_CURRENT, | ||||||
|  |                     false | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |             .setSilent(true) // Avoid creating noise for individual stream notifications. | ||||||
|  |             .build() | ||||||
|  |     } | ||||||
|  |  | ||||||
|     companion object { |     companion object { | ||||||
|         /** |         /** | ||||||
|          * Check whether notifications are enabled on the device. |          * Check whether notifications are enabled on the device. | ||||||
| @@ -124,9 +172,7 @@ class NotificationHelper(val context: Context) { | |||||||
|         fun areNotificationsEnabledOnDevice(context: Context): Boolean { |         fun areNotificationsEnabledOnDevice(context: Context): Boolean { | ||||||
|             return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |             return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||||
|                 val channelId = context.getString(R.string.streams_notification_channel_id) |                 val channelId = context.getString(R.string.streams_notification_channel_id) | ||||||
|                 val manager = context.getSystemService( |                 val manager = context.getSystemService<NotificationManager>()!! | ||||||
|                     Context.NOTIFICATION_SERVICE |  | ||||||
|                 ) as NotificationManager |  | ||||||
|                 val enabled = manager.areNotificationsEnabled() |                 val enabled = manager.areNotificationsEnabled() | ||||||
|                 val channel = manager.getNotificationChannel(channelId) |                 val channel = manager.getNotificationChannel(channelId) | ||||||
|                 val importance = channel?.importance |                 val importance = channel?.importance | ||||||
|   | |||||||
| @@ -55,7 +55,7 @@ class NotificationWorker( | |||||||
|             .map { feedUpdateInfoList -> |             .map { feedUpdateInfoList -> | ||||||
|                 // display notifications for each feedUpdateInfo (i.e. channel) |                 // display notifications for each feedUpdateInfo (i.e. channel) | ||||||
|                 feedUpdateInfoList.forEach { feedUpdateInfo -> |                 feedUpdateInfoList.forEach { feedUpdateInfo -> | ||||||
|                     notificationHelper.displayNewStreamsNotification(feedUpdateInfo) |                     notificationHelper.displayNewStreamsNotifications(feedUpdateInfo) | ||||||
|                 } |                 } | ||||||
|                 return@map Result.success() |                 return@map Result.success() | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -563,11 +563,8 @@ public final class NavigationHelper { | |||||||
|                                        @Nullable final PlayQueue playQueue, |                                        @Nullable final PlayQueue playQueue, | ||||||
|                                        final boolean switchingPlayers) { |                                        final boolean switchingPlayers) { | ||||||
|  |  | ||||||
|         final Intent intent = getOpenIntent(context, url, serviceId, |         final Intent intent = getStreamIntent(context, serviceId, url, title) | ||||||
|                 StreamingService.LinkType.STREAM); |                 .putExtra(VideoDetailFragment.KEY_SWITCHING_PLAYERS, switchingPlayers); | ||||||
|         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |  | ||||||
|         intent.putExtra(Constants.KEY_TITLE, title); |  | ||||||
|         intent.putExtra(VideoDetailFragment.KEY_SWITCHING_PLAYERS, switchingPlayers); |  | ||||||
|  |  | ||||||
|         if (playQueue != null) { |         if (playQueue != null) { | ||||||
|             final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class); |             final String cacheKey = SerializedCache.getInstance().put(playQueue, PlayQueue.class); | ||||||
| @@ -680,6 +677,15 @@ public final class NavigationHelper { | |||||||
|         return getOpenIntent(context, url, serviceId, StreamingService.LinkType.CHANNEL); |         return getOpenIntent(context, url, serviceId, StreamingService.LinkType.CHANNEL); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static Intent getStreamIntent(final Context context, | ||||||
|  |                                          final int serviceId, | ||||||
|  |                                          final String url, | ||||||
|  |                                          @Nullable final String title) { | ||||||
|  |         return getOpenIntent(context, url, serviceId, StreamingService.LinkType.STREAM) | ||||||
|  |                 .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) | ||||||
|  |                 .putExtra(Constants.KEY_TITLE, title); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Finish this <code>Activity</code> as well as all <code>Activities</code> running below it |      * Finish this <code>Activity</code> as well as all <code>Activities</code> running below it | ||||||
|      * and then start <code>MainActivity</code>. |      * and then start <code>MainActivity</code>. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user