Declare foreground service type for DownloadService
This ensures the DownloadService stays functional on Android 14 where defining this type is required. On Android 14 and above, the app also needs to define the DATA_SYNC permission, which is added to the demo app as well. In the future, this service type will no longer be supported and DownloadService needs to be rewritten with another background scheduling framework. Issue: google/ExoPlayer#11239 PiperOrigin-RevId: 548994842
This commit is contained in:
parent
035934c6d4
commit
8064c6df83
@ -115,6 +115,11 @@
|
||||
playback if a suitable device is connected within a configurable timeout
|
||||
(default is 5 minutes).
|
||||
* Downloads:
|
||||
* Declare "data sync" foreground service type for `DownloadService` for
|
||||
Android 14 compatibility. When using this service, the app also needs to
|
||||
add `dataSync` as `foregroundServiceType` in the manifest and add the
|
||||
`FOREGROUND_SERVICE_DATA_SYNC` permission
|
||||
([#11239](https://github.com/google/ExoPlayer/issues/11239)).
|
||||
* OkHttp Extension:
|
||||
* Cronet Extension:
|
||||
* RTMP Extension:
|
||||
|
@ -23,6 +23,7 @@
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
||||
<uses-feature android:name="android.software.leanback" android:required="false"/>
|
||||
@ -94,7 +95,8 @@
|
||||
</activity>
|
||||
|
||||
<service android:name=".DemoDownloadService"
|
||||
android:exported="false">
|
||||
android:exported="false"
|
||||
android:foregroundServiceType="dataSync">
|
||||
<intent-filter>
|
||||
<action android:name="androidx.media3.exoplayer.downloadService.action.RESTART"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
@ -36,6 +36,8 @@ import static java.lang.Math.min;
|
||||
import android.Manifest.permission;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.Notification;
|
||||
import android.app.Service;
|
||||
import android.app.UiModeManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
@ -298,6 +300,36 @@ public final class Util {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the notification required for a foreground service.
|
||||
*
|
||||
* @param service The foreground {@link Service}.
|
||||
* @param notificationId The notification id.
|
||||
* @param notification The {@link Notification}.
|
||||
* @param foregroundServiceType The foreground service type defined in {@link
|
||||
* android.content.pm.ServiceInfo}.
|
||||
* @param foregroundServiceManifestType The required foreground service type string for the {@code
|
||||
* <service>} element in the manifest.
|
||||
*/
|
||||
@UnstableApi
|
||||
public static void setForegroundServiceNotification(
|
||||
Service service,
|
||||
int notificationId,
|
||||
Notification notification,
|
||||
int foregroundServiceType,
|
||||
String foregroundServiceManifestType) {
|
||||
if (Util.SDK_INT >= 29) {
|
||||
Api29.startForeground(
|
||||
service,
|
||||
notificationId,
|
||||
notification,
|
||||
foregroundServiceType,
|
||||
foregroundServiceManifestType);
|
||||
} else {
|
||||
service.startForeground(notificationId, notification);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether it's necessary to request the {@link permission#READ_EXTERNAL_STORAGE}
|
||||
* permission read the specified {@link Uri}s, requesting the permission if necessary.
|
||||
@ -3356,4 +3388,29 @@ public final class Util {
|
||||
return resources.getDrawable(res, context.getTheme());
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(29)
|
||||
private static class Api29 {
|
||||
|
||||
@DoNotInline
|
||||
public static void startForeground(
|
||||
Service mediaSessionService,
|
||||
int notificationId,
|
||||
Notification notification,
|
||||
int foregroundServiceType,
|
||||
String foregroundServiceManifestType) {
|
||||
try {
|
||||
// startForeground() will throw if the service's foregroundServiceType is not defined.
|
||||
mediaSessionService.startForeground(notificationId, notification, foregroundServiceType);
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"The service must be declared with a foregroundServiceType that includes "
|
||||
+ foregroundServiceManifestType);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private Api29() {}
|
||||
}
|
||||
}
|
||||
|
@ -17,11 +17,13 @@ package androidx.media3.exoplayer.offline;
|
||||
|
||||
import static androidx.media3.exoplayer.offline.Download.STOP_REASON_NONE;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ServiceInfo;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
@ -910,6 +912,7 @@ public abstract class DownloadService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi") // Using compile time constant FOREGROUND_SERVICE_TYPE_DATA_SYNC
|
||||
private void update() {
|
||||
DownloadManager downloadManager =
|
||||
Assertions.checkNotNull(downloadManagerHelper).downloadManager;
|
||||
@ -917,7 +920,12 @@ public abstract class DownloadService extends Service {
|
||||
@RequirementFlags int notMetRequirements = downloadManager.getNotMetRequirements();
|
||||
Notification notification = getForegroundNotification(downloads, notMetRequirements);
|
||||
if (!notificationDisplayed) {
|
||||
startForeground(notificationId, notification);
|
||||
Util.setForegroundServiceNotification(
|
||||
/* service= */ DownloadService.this,
|
||||
notificationId,
|
||||
notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC,
|
||||
"dataSync");
|
||||
notificationDisplayed = true;
|
||||
} else {
|
||||
// Update the notification via NotificationManager rather than by repeatedly calling
|
||||
|
@ -19,6 +19,7 @@ import static android.app.Service.STOP_FOREGROUND_DETACH;
|
||||
import static android.app.Service.STOP_FOREGROUND_REMOVE;
|
||||
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Notification;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ServiceInfo;
|
||||
@ -346,14 +347,15 @@ import java.util.concurrent.TimeoutException;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("InlinedApi") // Using compile time constant FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
|
||||
private void startForeground(MediaNotification mediaNotification) {
|
||||
ContextCompat.startForegroundService(mediaSessionService, startSelfIntent);
|
||||
if (Util.SDK_INT >= 29) {
|
||||
Api29.startForeground(mediaSessionService, mediaNotification);
|
||||
} else {
|
||||
mediaSessionService.startForeground(
|
||||
mediaNotification.notificationId, mediaNotification.notification);
|
||||
}
|
||||
Util.setForegroundServiceNotification(
|
||||
mediaSessionService,
|
||||
mediaNotification.notificationId,
|
||||
mediaNotification.notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK,
|
||||
"mediaPlayback");
|
||||
startedInForeground = true;
|
||||
}
|
||||
|
||||
@ -380,29 +382,4 @@ import java.util.concurrent.TimeoutException;
|
||||
|
||||
private Api24() {}
|
||||
}
|
||||
|
||||
@RequiresApi(29)
|
||||
private static class Api29 {
|
||||
|
||||
@DoNotInline
|
||||
public static void startForeground(
|
||||
MediaSessionService mediaSessionService, MediaNotification mediaNotification) {
|
||||
try {
|
||||
// startForeground() will throw if the service's foregroundServiceType is not defined in the
|
||||
// manifest to include mediaPlayback.
|
||||
mediaSessionService.startForeground(
|
||||
mediaNotification.notificationId,
|
||||
mediaNotification.notification,
|
||||
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK);
|
||||
} catch (RuntimeException e) {
|
||||
Log.e(
|
||||
TAG,
|
||||
"The service must be declared with a foregroundServiceType that includes "
|
||||
+ " mediaPlayback");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private Api29() {}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user