mirror of
https://github.com/samsonjs/media.git
synced 2026-03-27 09:45:47 +00:00
Fix notifications to avoid flicker on KitKat
On KitKat you need to reuse the same notification builder when generating a notification that's intended to replace a previous one. See: https://stackoverflow.com/questions/6406730/updating-an-ongoing-notification-quietly PiperOrigin-RevId: 232503682
This commit is contained in:
parent
391f2bb6c2
commit
e3981ec484
5 changed files with 284 additions and 161 deletions
|
|
@ -43,6 +43,10 @@
|
|||
and `useSurfaceYuvOutput`.
|
||||
* Change signature of `PlayerNotificationManager.NotificationListener` to better
|
||||
fit service requirements. Remove ability to set a custom stop action.
|
||||
* Fix issues with flickering notifications on KitKat.
|
||||
`PlayerNotificationManager` has been fixed. Apps using
|
||||
`DownloadNotificationUtil` should switch to using
|
||||
`DownloadNotificationHelper`.
|
||||
|
||||
### 2.9.5 ###
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import com.google.android.exoplayer2.offline.DownloadManager;
|
|||
import com.google.android.exoplayer2.offline.DownloadService;
|
||||
import com.google.android.exoplayer2.offline.DownloadState;
|
||||
import com.google.android.exoplayer2.scheduler.PlatformScheduler;
|
||||
import com.google.android.exoplayer2.ui.DownloadNotificationUtil;
|
||||
import com.google.android.exoplayer2.ui.DownloadNotificationHelper;
|
||||
import com.google.android.exoplayer2.util.NotificationUtil;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
|
|
@ -33,6 +33,8 @@ public class DemoDownloadService extends DownloadService {
|
|||
|
||||
private static int nextNotificationId = FOREGROUND_NOTIFICATION_ID + 1;
|
||||
|
||||
private DownloadNotificationHelper notificationHelper;
|
||||
|
||||
public DemoDownloadService() {
|
||||
super(
|
||||
FOREGROUND_NOTIFICATION_ID,
|
||||
|
|
@ -42,6 +44,12 @@ public class DemoDownloadService extends DownloadService {
|
|||
nextNotificationId = FOREGROUND_NOTIFICATION_ID + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
notificationHelper = new DownloadNotificationHelper(this, CHANNEL_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DownloadManager getDownloadManager() {
|
||||
return ((DemoApplication) getApplication()).getDownloadManager();
|
||||
|
|
@ -54,13 +62,8 @@ public class DemoDownloadService extends DownloadService {
|
|||
|
||||
@Override
|
||||
protected Notification getForegroundNotification(DownloadState[] downloadStates) {
|
||||
return DownloadNotificationUtil.buildProgressNotification(
|
||||
/* context= */ this,
|
||||
R.drawable.ic_download,
|
||||
CHANNEL_ID,
|
||||
/* contentIntent= */ null,
|
||||
/* message= */ null,
|
||||
downloadStates);
|
||||
return notificationHelper.buildProgressNotification(
|
||||
R.drawable.ic_download, /* contentIntent= */ null, /* message= */ null, downloadStates);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -68,18 +71,14 @@ public class DemoDownloadService extends DownloadService {
|
|||
Notification notification;
|
||||
if (downloadState.state == DownloadState.STATE_COMPLETED) {
|
||||
notification =
|
||||
DownloadNotificationUtil.buildDownloadCompletedNotification(
|
||||
/* context= */ this,
|
||||
notificationHelper.buildDownloadCompletedNotification(
|
||||
R.drawable.ic_download_done,
|
||||
CHANNEL_ID,
|
||||
/* contentIntent= */ null,
|
||||
Util.fromUtf8Bytes(downloadState.customMetadata));
|
||||
} else if (downloadState.state == DownloadState.STATE_FAILED) {
|
||||
notification =
|
||||
DownloadNotificationUtil.buildDownloadFailedNotification(
|
||||
/* context= */ this,
|
||||
notificationHelper.buildDownloadFailedNotification(
|
||||
R.drawable.ic_download_done,
|
||||
CHANNEL_ID,
|
||||
/* contentIntent= */ null,
|
||||
Util.fromUtf8Bytes(downloadState.customMetadata));
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.ui;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.offline.DownloadState;
|
||||
|
||||
/** Helper for creating download notifications. */
|
||||
public final class DownloadNotificationHelper {
|
||||
|
||||
private static final @StringRes int NULL_STRING_ID = 0;
|
||||
|
||||
private final Context context;
|
||||
private final NotificationCompat.Builder notificationBuilder;
|
||||
|
||||
/**
|
||||
* @param context A context.
|
||||
* @param channelId The id of the notification channel to use.
|
||||
*/
|
||||
public DownloadNotificationHelper(Context context, String channelId) {
|
||||
context = context.getApplicationContext();
|
||||
this.context = context;
|
||||
this.notificationBuilder = new NotificationCompat.Builder(context, channelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a progress notification for the given download states.
|
||||
*
|
||||
* @param smallIcon A small icon for the notification.
|
||||
* @param contentIntent An optional content intent to send when the notification is clicked.
|
||||
* @param message An optional message to display on the notification.
|
||||
* @param downloadStates The download states.
|
||||
* @return The notification.
|
||||
*/
|
||||
public Notification buildProgressNotification(
|
||||
@DrawableRes int smallIcon,
|
||||
@Nullable PendingIntent contentIntent,
|
||||
@Nullable String message,
|
||||
DownloadState[] downloadStates) {
|
||||
float totalPercentage = 0;
|
||||
int downloadTaskCount = 0;
|
||||
boolean allDownloadPercentagesUnknown = true;
|
||||
boolean haveDownloadedBytes = false;
|
||||
boolean haveDownloadTasks = false;
|
||||
boolean haveRemoveTasks = false;
|
||||
for (DownloadState downloadState : downloadStates) {
|
||||
if (downloadState.state == DownloadState.STATE_REMOVING
|
||||
|| downloadState.state == DownloadState.STATE_RESTARTING
|
||||
|| downloadState.state == DownloadState.STATE_REMOVED) {
|
||||
haveRemoveTasks = true;
|
||||
continue;
|
||||
}
|
||||
if (downloadState.state != DownloadState.STATE_DOWNLOADING
|
||||
&& downloadState.state != DownloadState.STATE_COMPLETED) {
|
||||
continue;
|
||||
}
|
||||
haveDownloadTasks = true;
|
||||
if (downloadState.downloadPercentage != C.PERCENTAGE_UNSET) {
|
||||
allDownloadPercentagesUnknown = false;
|
||||
totalPercentage += downloadState.downloadPercentage;
|
||||
}
|
||||
haveDownloadedBytes |= downloadState.downloadedBytes > 0;
|
||||
downloadTaskCount++;
|
||||
}
|
||||
|
||||
int titleStringId =
|
||||
haveDownloadTasks
|
||||
? R.string.exo_download_downloading
|
||||
: (haveRemoveTasks ? R.string.exo_download_removing : NULL_STRING_ID);
|
||||
int progress = 0;
|
||||
boolean indeterminate = true;
|
||||
if (haveDownloadTasks) {
|
||||
progress = (int) (totalPercentage / downloadTaskCount);
|
||||
indeterminate = allDownloadPercentagesUnknown && haveDownloadedBytes;
|
||||
}
|
||||
return buildNotification(
|
||||
smallIcon,
|
||||
contentIntent,
|
||||
message,
|
||||
titleStringId,
|
||||
progress,
|
||||
indeterminate,
|
||||
/* ongoing= */ true,
|
||||
/* showWhen= */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a notification for a completed download.
|
||||
*
|
||||
* @param smallIcon A small icon for the notifications.
|
||||
* @param contentIntent An optional content intent to send when the notification is clicked.
|
||||
* @param message An optional message to display on the notification.
|
||||
* @return The notification.
|
||||
*/
|
||||
public Notification buildDownloadCompletedNotification(
|
||||
@DrawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message) {
|
||||
int titleStringId = R.string.exo_download_completed;
|
||||
return buildEndStateNotification(smallIcon, contentIntent, message, titleStringId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a notification for a failed download.
|
||||
*
|
||||
* @param smallIcon A small icon for the notifications.
|
||||
* @param contentIntent An optional content intent to send when the notification is clicked.
|
||||
* @param message An optional message to display on the notification.
|
||||
* @return The notification.
|
||||
*/
|
||||
public Notification buildDownloadFailedNotification(
|
||||
@DrawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message) {
|
||||
@StringRes int titleStringId = R.string.exo_download_failed;
|
||||
return buildEndStateNotification(smallIcon, contentIntent, message, titleStringId);
|
||||
}
|
||||
|
||||
private Notification buildEndStateNotification(
|
||||
@DrawableRes int smallIcon,
|
||||
@Nullable PendingIntent contentIntent,
|
||||
@Nullable String message,
|
||||
@StringRes int titleStringId) {
|
||||
return buildNotification(
|
||||
smallIcon,
|
||||
contentIntent,
|
||||
message,
|
||||
titleStringId,
|
||||
/* progress= */ 0,
|
||||
/* indeterminateProgress= */ false,
|
||||
/* ongoing= */ false,
|
||||
/* showWhen= */ true);
|
||||
}
|
||||
|
||||
private Notification buildNotification(
|
||||
@DrawableRes int smallIcon,
|
||||
@Nullable PendingIntent contentIntent,
|
||||
@Nullable String message,
|
||||
@StringRes int titleStringId,
|
||||
int progress,
|
||||
boolean indeterminateProgress,
|
||||
boolean ongoing,
|
||||
boolean showWhen) {
|
||||
notificationBuilder.setSmallIcon(smallIcon);
|
||||
notificationBuilder.setContentTitle(
|
||||
titleStringId == NULL_STRING_ID ? null : context.getResources().getString(titleStringId));
|
||||
notificationBuilder.setContentIntent(contentIntent);
|
||||
notificationBuilder.setStyle(
|
||||
message == null ? null : new NotificationCompat.BigTextStyle().bigText(message));
|
||||
notificationBuilder.setProgress(/* max= */ 100, progress, indeterminateProgress);
|
||||
notificationBuilder.setOngoing(ongoing);
|
||||
notificationBuilder.setShowWhen(showWhen);
|
||||
return notificationBuilder.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -20,16 +20,16 @@ import android.app.PendingIntent;
|
|||
import android.content.Context;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.offline.DownloadState;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
||||
/** Helper for creating download notifications. */
|
||||
/**
|
||||
* @deprecated Using this class can cause notifications to flicker on devices with {@link
|
||||
* Util#SDK_INT} < 21. Use {@link DownloadNotificationHelper} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public final class DownloadNotificationUtil {
|
||||
|
||||
private static final @StringRes int NULL_STRING_ID = 0;
|
||||
|
||||
private DownloadNotificationUtil() {}
|
||||
|
||||
/**
|
||||
|
|
@ -37,8 +37,7 @@ public final class DownloadNotificationUtil {
|
|||
*
|
||||
* @param context A context for accessing resources.
|
||||
* @param smallIcon A small icon for the notification.
|
||||
* @param channelId The id of the notification channel to use. Only required for API level 26 and
|
||||
* above.
|
||||
* @param channelId The id of the notification channel to use.
|
||||
* @param contentIntent An optional content intent to send when the notification is clicked.
|
||||
* @param message An optional message to display on the notification.
|
||||
* @param downloadStates The download states.
|
||||
|
|
@ -51,50 +50,8 @@ public final class DownloadNotificationUtil {
|
|||
@Nullable PendingIntent contentIntent,
|
||||
@Nullable String message,
|
||||
DownloadState[] downloadStates) {
|
||||
float totalPercentage = 0;
|
||||
int downloadTaskCount = 0;
|
||||
boolean allDownloadPercentagesUnknown = true;
|
||||
boolean haveDownloadedBytes = false;
|
||||
boolean haveDownloadTasks = false;
|
||||
boolean haveRemoveTasks = false;
|
||||
for (DownloadState downloadState : downloadStates) {
|
||||
if (downloadState.state == DownloadState.STATE_REMOVING
|
||||
|| downloadState.state == DownloadState.STATE_RESTARTING
|
||||
|| downloadState.state == DownloadState.STATE_REMOVED) {
|
||||
haveRemoveTasks = true;
|
||||
continue;
|
||||
}
|
||||
if (downloadState.state != DownloadState.STATE_DOWNLOADING
|
||||
&& downloadState.state != DownloadState.STATE_COMPLETED) {
|
||||
continue;
|
||||
}
|
||||
haveDownloadTasks = true;
|
||||
if (downloadState.downloadPercentage != C.PERCENTAGE_UNSET) {
|
||||
allDownloadPercentagesUnknown = false;
|
||||
totalPercentage += downloadState.downloadPercentage;
|
||||
}
|
||||
haveDownloadedBytes |= downloadState.downloadedBytes > 0;
|
||||
downloadTaskCount++;
|
||||
}
|
||||
|
||||
int titleStringId =
|
||||
haveDownloadTasks
|
||||
? R.string.exo_download_downloading
|
||||
: (haveRemoveTasks ? R.string.exo_download_removing : NULL_STRING_ID);
|
||||
NotificationCompat.Builder notificationBuilder =
|
||||
newNotificationBuilder(
|
||||
context, smallIcon, channelId, contentIntent, message, titleStringId);
|
||||
|
||||
int progress = 0;
|
||||
boolean indeterminate = true;
|
||||
if (haveDownloadTasks) {
|
||||
progress = (int) (totalPercentage / downloadTaskCount);
|
||||
indeterminate = allDownloadPercentagesUnknown && haveDownloadedBytes;
|
||||
}
|
||||
notificationBuilder.setProgress(/* max= */ 100, progress, indeterminate);
|
||||
notificationBuilder.setOngoing(true);
|
||||
notificationBuilder.setShowWhen(false);
|
||||
return notificationBuilder.build();
|
||||
return new DownloadNotificationHelper(context, channelId)
|
||||
.buildProgressNotification(smallIcon, contentIntent, message, downloadStates);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -102,8 +59,7 @@ public final class DownloadNotificationUtil {
|
|||
*
|
||||
* @param context A context for accessing resources.
|
||||
* @param smallIcon A small icon for the notifications.
|
||||
* @param channelId The id of the notification channel to use. Only required for API level 26 and
|
||||
* above.
|
||||
* @param channelId The id of the notification channel to use.
|
||||
* @param contentIntent An optional content intent to send when the notification is clicked.
|
||||
* @param message An optional message to display on the notification.
|
||||
* @return The notification.
|
||||
|
|
@ -114,10 +70,8 @@ public final class DownloadNotificationUtil {
|
|||
String channelId,
|
||||
@Nullable PendingIntent contentIntent,
|
||||
@Nullable String message) {
|
||||
int titleStringId = R.string.exo_download_completed;
|
||||
return newNotificationBuilder(
|
||||
context, smallIcon, channelId, contentIntent, message, titleStringId)
|
||||
.build();
|
||||
return new DownloadNotificationHelper(context, channelId)
|
||||
.buildDownloadCompletedNotification(smallIcon, contentIntent, message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -125,8 +79,7 @@ public final class DownloadNotificationUtil {
|
|||
*
|
||||
* @param context A context for accessing resources.
|
||||
* @param smallIcon A small icon for the notifications.
|
||||
* @param channelId The id of the notification channel to use. Only required for API level 26 and
|
||||
* above.
|
||||
* @param channelId The id of the notification channel to use.
|
||||
* @param contentIntent An optional content intent to send when the notification is clicked.
|
||||
* @param message An optional message to display on the notification.
|
||||
* @return The notification.
|
||||
|
|
@ -137,30 +90,7 @@ public final class DownloadNotificationUtil {
|
|||
String channelId,
|
||||
@Nullable PendingIntent contentIntent,
|
||||
@Nullable String message) {
|
||||
@StringRes int titleStringId = R.string.exo_download_failed;
|
||||
return newNotificationBuilder(
|
||||
context, smallIcon, channelId, contentIntent, message, titleStringId)
|
||||
.build();
|
||||
}
|
||||
|
||||
private static NotificationCompat.Builder newNotificationBuilder(
|
||||
Context context,
|
||||
@DrawableRes int smallIcon,
|
||||
String channelId,
|
||||
@Nullable PendingIntent contentIntent,
|
||||
@Nullable String message,
|
||||
@StringRes int titleStringId) {
|
||||
NotificationCompat.Builder notificationBuilder =
|
||||
new NotificationCompat.Builder(context, channelId).setSmallIcon(smallIcon);
|
||||
if (titleStringId != NULL_STRING_ID) {
|
||||
notificationBuilder.setContentTitle(context.getResources().getString(titleStringId));
|
||||
}
|
||||
if (contentIntent != null) {
|
||||
notificationBuilder.setContentIntent(contentIntent);
|
||||
}
|
||||
if (message != null) {
|
||||
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(message));
|
||||
}
|
||||
return notificationBuilder;
|
||||
return new DownloadNotificationHelper(context, channelId)
|
||||
.buildDownloadFailedNotification(smallIcon, contentIntent, message);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -338,6 +338,7 @@ public class PlayerNotificationManager {
|
|||
|
||||
private final Context context;
|
||||
private final String channelId;
|
||||
private final NotificationCompat.Builder builder;
|
||||
private final int notificationId;
|
||||
private final MediaDescriptionAdapter mediaDescriptionAdapter;
|
||||
private final @Nullable CustomActionReceiver customActionReceiver;
|
||||
|
|
@ -530,12 +531,14 @@ public class PlayerNotificationManager {
|
|||
MediaDescriptionAdapter mediaDescriptionAdapter,
|
||||
@Nullable NotificationListener notificationListener,
|
||||
@Nullable CustomActionReceiver customActionReceiver) {
|
||||
this.context = context.getApplicationContext();
|
||||
context = context.getApplicationContext();
|
||||
this.context = context;
|
||||
this.channelId = channelId;
|
||||
this.notificationId = notificationId;
|
||||
this.mediaDescriptionAdapter = mediaDescriptionAdapter;
|
||||
this.notificationListener = notificationListener;
|
||||
this.customActionReceiver = customActionReceiver;
|
||||
builder = new NotificationCompat.Builder(context, channelId);
|
||||
controlDispatcher = new DefaultControlDispatcher();
|
||||
window = new Timeline.Window();
|
||||
instanceId = instanceIdCounter++;
|
||||
|
|
@ -887,7 +890,7 @@ public class PlayerNotificationManager {
|
|||
private Notification startOrUpdateNotification(@Nullable Bitmap bitmap) {
|
||||
Player player = this.player;
|
||||
boolean ongoing = getOngoing(player);
|
||||
Notification notification = createNotification(player, ongoing, bitmap);
|
||||
Notification notification = createNotification(player, builder, ongoing, bitmap);
|
||||
if (notification == null) {
|
||||
stopNotification(/* dismissedByUser= */ false);
|
||||
return null;
|
||||
|
|
@ -923,6 +926,11 @@ public class PlayerNotificationManager {
|
|||
* Creates the notification given the current player state.
|
||||
*
|
||||
* @param player The player for which state to build a notification.
|
||||
* @param builder A builder that can optionally be used for creating the notification. The same
|
||||
* builder is passed each time this method is called, since reusing the same builder can
|
||||
* prevent notification flicker when {@code Util#SDK_INT} < 21. This means implementations
|
||||
* must take care to ensure anything set on the builder during a previous call is cleared, if
|
||||
* no longer required.
|
||||
* @param ongoing Whether the notification should be ongoing.
|
||||
* @param largeIcon The large icon to be used.
|
||||
* @return The {@link Notification} which has been built, or {@code null} if no notification
|
||||
|
|
@ -930,11 +938,15 @@ public class PlayerNotificationManager {
|
|||
*/
|
||||
@Nullable
|
||||
protected Notification createNotification(
|
||||
Player player, boolean ongoing, @Nullable Bitmap largeIcon) {
|
||||
Player player,
|
||||
NotificationCompat.Builder builder,
|
||||
boolean ongoing,
|
||||
@Nullable Bitmap largeIcon) {
|
||||
if (player.getPlaybackState() == Player.STATE_IDLE) {
|
||||
return null;
|
||||
}
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId);
|
||||
|
||||
builder.mActions.clear();
|
||||
List<String> actionNames = getActions(player);
|
||||
for (int i = 0; i < actionNames.size(); i++) {
|
||||
String actionName = actionNames.get(i);
|
||||
|
|
@ -946,7 +958,7 @@ public class PlayerNotificationManager {
|
|||
builder.addAction(action);
|
||||
}
|
||||
}
|
||||
// Create a media style notification.
|
||||
|
||||
MediaStyle mediaStyle = new MediaStyle();
|
||||
if (mediaSessionToken != null) {
|
||||
mediaStyle.setMediaSession(mediaSessionToken);
|
||||
|
|
@ -955,9 +967,11 @@ public class PlayerNotificationManager {
|
|||
// Configure dismiss action prior to API 21 ('x' button).
|
||||
mediaStyle.setShowCancelButton(!ongoing);
|
||||
mediaStyle.setCancelButtonIntent(dismissPendingIntent);
|
||||
builder.setStyle(mediaStyle);
|
||||
|
||||
// Set intent which is sent if the user selects 'clear all'
|
||||
builder.setDeleteIntent(dismissPendingIntent);
|
||||
builder.setStyle(mediaStyle);
|
||||
|
||||
// Set notification properties from getters.
|
||||
builder
|
||||
.setBadgeIconType(badgeIconType)
|
||||
|
|
@ -968,7 +982,10 @@ public class PlayerNotificationManager {
|
|||
.setVisibility(visibility)
|
||||
.setPriority(priority)
|
||||
.setDefaults(defaults);
|
||||
if (useChronometer
|
||||
|
||||
// Changing "showWhen" causes notification flicker if SDK_INT < 21.
|
||||
if (Util.SDK_INT >= 21
|
||||
&& useChronometer
|
||||
&& !player.isPlayingAd()
|
||||
&& !player.isCurrentWindowDynamic()
|
||||
&& player.getPlayWhenReady()
|
||||
|
|
@ -980,6 +997,7 @@ public class PlayerNotificationManager {
|
|||
} else {
|
||||
builder.setShowWhen(false).setUsesChronometer(false);
|
||||
}
|
||||
|
||||
// Set media specific notification properties from MediaDescriptionAdapter.
|
||||
builder.setContentTitle(mediaDescriptionAdapter.getCurrentContentTitle(player));
|
||||
builder.setContentText(mediaDescriptionAdapter.getCurrentContentText(player));
|
||||
|
|
@ -989,13 +1007,9 @@ public class PlayerNotificationManager {
|
|||
mediaDescriptionAdapter.getCurrentLargeIcon(
|
||||
player, new BitmapCallback(++currentNotificationTag));
|
||||
}
|
||||
if (largeIcon != null) {
|
||||
builder.setLargeIcon(largeIcon);
|
||||
}
|
||||
PendingIntent contentIntent = mediaDescriptionAdapter.createCurrentContentIntent(player);
|
||||
if (contentIntent != null) {
|
||||
builder.setContentIntent(contentIntent);
|
||||
}
|
||||
setLargeIcon(builder, largeIcon);
|
||||
builder.setContentIntent(mediaDescriptionAdapter.createCurrentContentIntent(player));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
|
@ -1086,54 +1100,6 @@ public class PlayerNotificationManager {
|
|||
&& player.getPlayWhenReady();
|
||||
}
|
||||
|
||||
private static Map<String, NotificationCompat.Action> createPlaybackActions(
|
||||
Context context, int instanceId) {
|
||||
Map<String, NotificationCompat.Action> actions = new HashMap<>();
|
||||
actions.put(
|
||||
ACTION_PLAY,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_play,
|
||||
context.getString(R.string.exo_controls_play_description),
|
||||
createBroadcastIntent(ACTION_PLAY, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_PAUSE,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_pause,
|
||||
context.getString(R.string.exo_controls_pause_description),
|
||||
createBroadcastIntent(ACTION_PAUSE, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_STOP,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_stop,
|
||||
context.getString(R.string.exo_controls_stop_description),
|
||||
createBroadcastIntent(ACTION_STOP, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_REWIND,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_rewind,
|
||||
context.getString(R.string.exo_controls_rewind_description),
|
||||
createBroadcastIntent(ACTION_REWIND, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_FAST_FORWARD,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_fastforward,
|
||||
context.getString(R.string.exo_controls_fastforward_description),
|
||||
createBroadcastIntent(ACTION_FAST_FORWARD, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_PREVIOUS,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_previous,
|
||||
context.getString(R.string.exo_controls_previous_description),
|
||||
createBroadcastIntent(ACTION_PREVIOUS, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_NEXT,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_next,
|
||||
context.getString(R.string.exo_controls_next_description),
|
||||
createBroadcastIntent(ACTION_NEXT, context, instanceId)));
|
||||
return actions;
|
||||
}
|
||||
|
||||
private void previous(Player player) {
|
||||
Timeline timeline = player.getCurrentTimeline();
|
||||
if (timeline.isEmpty() || player.isPlayingAd()) {
|
||||
|
|
@ -1196,6 +1162,54 @@ public class PlayerNotificationManager {
|
|||
&& player.getPlayWhenReady();
|
||||
}
|
||||
|
||||
private static Map<String, NotificationCompat.Action> createPlaybackActions(
|
||||
Context context, int instanceId) {
|
||||
Map<String, NotificationCompat.Action> actions = new HashMap<>();
|
||||
actions.put(
|
||||
ACTION_PLAY,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_play,
|
||||
context.getString(R.string.exo_controls_play_description),
|
||||
createBroadcastIntent(ACTION_PLAY, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_PAUSE,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_pause,
|
||||
context.getString(R.string.exo_controls_pause_description),
|
||||
createBroadcastIntent(ACTION_PAUSE, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_STOP,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_stop,
|
||||
context.getString(R.string.exo_controls_stop_description),
|
||||
createBroadcastIntent(ACTION_STOP, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_REWIND,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_rewind,
|
||||
context.getString(R.string.exo_controls_rewind_description),
|
||||
createBroadcastIntent(ACTION_REWIND, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_FAST_FORWARD,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_fastforward,
|
||||
context.getString(R.string.exo_controls_fastforward_description),
|
||||
createBroadcastIntent(ACTION_FAST_FORWARD, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_PREVIOUS,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_previous,
|
||||
context.getString(R.string.exo_controls_previous_description),
|
||||
createBroadcastIntent(ACTION_PREVIOUS, context, instanceId)));
|
||||
actions.put(
|
||||
ACTION_NEXT,
|
||||
new NotificationCompat.Action(
|
||||
R.drawable.exo_notification_next,
|
||||
context.getString(R.string.exo_controls_next_description),
|
||||
createBroadcastIntent(ACTION_NEXT, context, instanceId)));
|
||||
return actions;
|
||||
}
|
||||
|
||||
private static PendingIntent createBroadcastIntent(
|
||||
String action, Context context, int instanceId) {
|
||||
Intent intent = new Intent(action).setPackage(context.getPackageName());
|
||||
|
|
@ -1204,6 +1218,11 @@ public class PlayerNotificationManager {
|
|||
context, instanceId, intent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
}
|
||||
|
||||
@SuppressWarnings("nullness:argument.type.incompatible")
|
||||
private static void setLargeIcon(NotificationCompat.Builder builder, @Nullable Bitmap largeIcon) {
|
||||
builder.setLargeIcon(largeIcon);
|
||||
}
|
||||
|
||||
private class PlayerListener implements Player.EventListener {
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Reference in a new issue