1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.exoplayer2.ui; 17 18 import android.app.Notification; 19 import android.app.PendingIntent; 20 import android.content.Context; 21 import androidx.annotation.DrawableRes; 22 import androidx.annotation.Nullable; 23 import androidx.annotation.StringRes; 24 import androidx.core.app.NotificationCompat; 25 import com.google.android.exoplayer2.C; 26 import com.google.android.exoplayer2.offline.Download; 27 import java.util.List; 28 29 /** Helper for creating download notifications. */ 30 public final class DownloadNotificationHelper { 31 32 private static final @StringRes int NULL_STRING_ID = 0; 33 34 private final Context context; 35 private final NotificationCompat.Builder notificationBuilder; 36 37 /** 38 * @param context A context. 39 * @param channelId The id of the notification channel to use. 40 */ DownloadNotificationHelper(Context context, String channelId)41 public DownloadNotificationHelper(Context context, String channelId) { 42 context = context.getApplicationContext(); 43 this.context = context; 44 this.notificationBuilder = new NotificationCompat.Builder(context, channelId); 45 } 46 47 /** 48 * Returns a progress notification for the given downloads. 49 * 50 * @param smallIcon A small icon for the notification. 51 * @param contentIntent An optional content intent to send when the notification is clicked. 52 * @param message An optional message to display on the notification. 53 * @param downloads The downloads. 54 * @return The notification. 55 */ buildProgressNotification( @rawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message, List<Download> downloads)56 public Notification buildProgressNotification( 57 @DrawableRes int smallIcon, 58 @Nullable PendingIntent contentIntent, 59 @Nullable String message, 60 List<Download> downloads) { 61 float totalPercentage = 0; 62 int downloadTaskCount = 0; 63 boolean allDownloadPercentagesUnknown = true; 64 boolean haveDownloadedBytes = false; 65 boolean haveDownloadTasks = false; 66 boolean haveRemoveTasks = false; 67 for (int i = 0; i < downloads.size(); i++) { 68 Download download = downloads.get(i); 69 if (download.state == Download.STATE_REMOVING) { 70 haveRemoveTasks = true; 71 continue; 72 } 73 if (download.state != Download.STATE_RESTARTING 74 && download.state != Download.STATE_DOWNLOADING) { 75 continue; 76 } 77 haveDownloadTasks = true; 78 float downloadPercentage = download.getPercentDownloaded(); 79 if (downloadPercentage != C.PERCENTAGE_UNSET) { 80 allDownloadPercentagesUnknown = false; 81 totalPercentage += downloadPercentage; 82 } 83 haveDownloadedBytes |= download.getBytesDownloaded() > 0; 84 downloadTaskCount++; 85 } 86 87 int titleStringId = 88 haveDownloadTasks 89 ? R.string.exo_download_downloading 90 : (haveRemoveTasks ? R.string.exo_download_removing : NULL_STRING_ID); 91 int progress = 0; 92 boolean indeterminate = true; 93 if (haveDownloadTasks) { 94 progress = (int) (totalPercentage / downloadTaskCount); 95 indeterminate = allDownloadPercentagesUnknown && haveDownloadedBytes; 96 } 97 return buildNotification( 98 smallIcon, 99 contentIntent, 100 message, 101 titleStringId, 102 /* maxProgress= */ 100, 103 progress, 104 indeterminate, 105 /* ongoing= */ true, 106 /* showWhen= */ false); 107 } 108 109 /** 110 * Returns a notification for a completed download. 111 * 112 * @param smallIcon A small icon for the notifications. 113 * @param contentIntent An optional content intent to send when the notification is clicked. 114 * @param message An optional message to display on the notification. 115 * @return The notification. 116 */ buildDownloadCompletedNotification( @rawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message)117 public Notification buildDownloadCompletedNotification( 118 @DrawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message) { 119 int titleStringId = R.string.exo_download_completed; 120 return buildEndStateNotification(smallIcon, contentIntent, message, titleStringId); 121 } 122 123 /** 124 * Returns a notification for a failed download. 125 * 126 * @param smallIcon A small icon for the notifications. 127 * @param contentIntent An optional content intent to send when the notification is clicked. 128 * @param message An optional message to display on the notification. 129 * @return The notification. 130 */ buildDownloadFailedNotification( @rawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message)131 public Notification buildDownloadFailedNotification( 132 @DrawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message) { 133 @StringRes int titleStringId = R.string.exo_download_failed; 134 return buildEndStateNotification(smallIcon, contentIntent, message, titleStringId); 135 } 136 buildEndStateNotification( @rawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message, @StringRes int titleStringId)137 private Notification buildEndStateNotification( 138 @DrawableRes int smallIcon, 139 @Nullable PendingIntent contentIntent, 140 @Nullable String message, 141 @StringRes int titleStringId) { 142 return buildNotification( 143 smallIcon, 144 contentIntent, 145 message, 146 titleStringId, 147 /* maxProgress= */ 0, 148 /* currentProgress= */ 0, 149 /* indeterminateProgress= */ false, 150 /* ongoing= */ false, 151 /* showWhen= */ true); 152 } 153 buildNotification( @rawableRes int smallIcon, @Nullable PendingIntent contentIntent, @Nullable String message, @StringRes int titleStringId, int maxProgress, int currentProgress, boolean indeterminateProgress, boolean ongoing, boolean showWhen)154 private Notification buildNotification( 155 @DrawableRes int smallIcon, 156 @Nullable PendingIntent contentIntent, 157 @Nullable String message, 158 @StringRes int titleStringId, 159 int maxProgress, 160 int currentProgress, 161 boolean indeterminateProgress, 162 boolean ongoing, 163 boolean showWhen) { 164 notificationBuilder.setSmallIcon(smallIcon); 165 notificationBuilder.setContentTitle( 166 titleStringId == NULL_STRING_ID ? null : context.getResources().getString(titleStringId)); 167 notificationBuilder.setContentIntent(contentIntent); 168 notificationBuilder.setStyle( 169 message == null ? null : new NotificationCompat.BigTextStyle().bigText(message)); 170 notificationBuilder.setProgress(maxProgress, currentProgress, indeterminateProgress); 171 notificationBuilder.setOngoing(ongoing); 172 notificationBuilder.setShowWhen(showWhen); 173 return notificationBuilder.build(); 174 } 175 } 176