Update DownloadService for Android 12
- If DownloadService is configured to run as a foreground service, it will remain started and in the foreground when downloads are waiting for requirements to be met, with a suitable "waiting for XYZ" message in the notification. This is necessary because new foreground service restrictions in Android 12 prevent to service from being restarted from the background. - Cases where requirements are not supported by the Scheduler will be handled in the same way, even on earlier versions of Android. So will cases where a Scheduler is not provided. - The Scheduler will still be used on earlier versions of Android where possible. Note: We could technically continue to use the old behavior on Android 12 in cases where the containing application still has a targetSdkVersion corresponding to Android 11 or earlier. However, in practice, there seems to be little value in doing this. PiperOrigin-RevId: 398720114
This commit is contained in:
parent
fecb8b7ec8
commit
a720380e77
@ -14,6 +14,10 @@
|
|||||||
* Move `Player.addListener(EventListener)` and
|
* Move `Player.addListener(EventListener)` and
|
||||||
`Player.removeListener(EventListener)` out of `Player` into subclasses.
|
`Player.removeListener(EventListener)` out of `Player` into subclasses.
|
||||||
* Android 12 compatibility:
|
* Android 12 compatibility:
|
||||||
|
* Keep `DownloadService` started and in the foreground whilst waiting for
|
||||||
|
requirements to be met on Android 12. This is necessary due to new
|
||||||
|
[foreground service launch restrictions](https://developer.android.com/about/versions/12/foreground-services).
|
||||||
|
`DownloadService.getScheduler` will not be called on Android 12 devices.
|
||||||
* Disable platform transcoding when playing content URIs on Android 12.
|
* Disable platform transcoding when playing content URIs on Android 12.
|
||||||
* Add `ExoPlayer.setVideoChangeFrameRateStrategy` to allow disabling of
|
* Add `ExoPlayer.setVideoChangeFrameRateStrategy` to allow disabling of
|
||||||
calls from the player to `Surface.setFrameRate`. This is useful for
|
calls from the player to `Surface.setFrameRate`. This is useful for
|
||||||
@ -23,6 +27,14 @@
|
|||||||
* `SubtitleView` no longer implements `TextOutput`. `SubtitleView`
|
* `SubtitleView` no longer implements `TextOutput`. `SubtitleView`
|
||||||
implements `Player.Listener`, so can be registered to a player with
|
implements `Player.Listener`, so can be registered to a player with
|
||||||
`Player.addListener`.
|
`Player.addListener`.
|
||||||
|
* Downloads and caching:
|
||||||
|
* Modify `DownloadService` behavior when `DownloadService.getScheduler`
|
||||||
|
returns `null`, or returns a `Scheduler` that does not support the
|
||||||
|
requirements for downloads to continue. In both cases, `DownloadService`
|
||||||
|
will now remain started and in the foreground whilst waiting for
|
||||||
|
requirements to be met.
|
||||||
|
* Modify `DownlaodService` behavior when running on Android 12 and above.
|
||||||
|
See the "Android 12 compatibility" section above.
|
||||||
* RTSP:
|
* RTSP:
|
||||||
* Support RFC4566 SDP attribute field grammar
|
* Support RFC4566 SDP attribute field grammar
|
||||||
([#9430](https://github.com/google/ExoPlayer/issues/9430)).
|
([#9430](https://github.com/google/ExoPlayer/issues/9430)).
|
||||||
|
@ -28,6 +28,7 @@ import android.os.Looper;
|
|||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import com.google.android.exoplayer2.scheduler.Requirements;
|
import com.google.android.exoplayer2.scheduler.Requirements;
|
||||||
|
import com.google.android.exoplayer2.scheduler.Requirements.RequirementFlags;
|
||||||
import com.google.android.exoplayer2.scheduler.Scheduler;
|
import com.google.android.exoplayer2.scheduler.Scheduler;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Log;
|
import com.google.android.exoplayer2.util.Log;
|
||||||
@ -36,6 +37,7 @@ import com.google.android.exoplayer2.util.Util;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||||
|
|
||||||
/** A {@link Service} for downloading media. */
|
/** A {@link Service} for downloading media. */
|
||||||
public abstract class DownloadService extends Service {
|
public abstract class DownloadService extends Service {
|
||||||
@ -179,8 +181,7 @@ public abstract class DownloadService extends Service {
|
|||||||
@StringRes private final int channelNameResourceId;
|
@StringRes private final int channelNameResourceId;
|
||||||
@StringRes private final int channelDescriptionResourceId;
|
@StringRes private final int channelDescriptionResourceId;
|
||||||
|
|
||||||
private @MonotonicNonNull Scheduler scheduler;
|
private @MonotonicNonNull DownloadManagerHelper downloadManagerHelper;
|
||||||
private @MonotonicNonNull DownloadManager downloadManager;
|
|
||||||
private int lastStartId;
|
private int lastStartId;
|
||||||
private boolean startedInForeground;
|
private boolean startedInForeground;
|
||||||
private boolean taskRemoved;
|
private boolean taskRemoved;
|
||||||
@ -191,8 +192,7 @@ public abstract class DownloadService extends Service {
|
|||||||
* Creates a DownloadService.
|
* Creates a DownloadService.
|
||||||
*
|
*
|
||||||
* <p>If {@code foregroundNotificationId} is {@link #FOREGROUND_NOTIFICATION_ID_NONE} then the
|
* <p>If {@code foregroundNotificationId} is {@link #FOREGROUND_NOTIFICATION_ID_NONE} then the
|
||||||
* service will only ever run in the background. No foreground notification will be displayed and
|
* service will only ever run in the background, and no foreground notification will be displayed.
|
||||||
* {@link #getScheduler()} will not be called.
|
|
||||||
*
|
*
|
||||||
* <p>If {@code foregroundNotificationId} is not {@link #FOREGROUND_NOTIFICATION_ID_NONE} then the
|
* <p>If {@code foregroundNotificationId} is not {@link #FOREGROUND_NOTIFICATION_ID_NONE} then the
|
||||||
* service will run in the foreground. The foreground notification will be updated at least as
|
* service will run in the foreground. The foreground notification will be updated at least as
|
||||||
@ -583,22 +583,19 @@ public abstract class DownloadService extends Service {
|
|||||||
@Nullable DownloadManagerHelper downloadManagerHelper = downloadManagerHelpers.get(clazz);
|
@Nullable DownloadManagerHelper downloadManagerHelper = downloadManagerHelpers.get(clazz);
|
||||||
if (downloadManagerHelper == null) {
|
if (downloadManagerHelper == null) {
|
||||||
boolean foregroundAllowed = foregroundNotificationUpdater != null;
|
boolean foregroundAllowed = foregroundNotificationUpdater != null;
|
||||||
@Nullable Scheduler scheduler = foregroundAllowed ? getScheduler() : null;
|
// See https://developer.android.com/about/versions/12/foreground-services.
|
||||||
if (scheduler != null) {
|
boolean canStartForegroundServiceFromBackground = Util.SDK_INT < 31;
|
||||||
this.scheduler = scheduler;
|
@Nullable
|
||||||
}
|
Scheduler scheduler =
|
||||||
downloadManager = getDownloadManager();
|
foregroundAllowed && canStartForegroundServiceFromBackground ? getScheduler() : null;
|
||||||
|
DownloadManager downloadManager = getDownloadManager();
|
||||||
downloadManager.resumeDownloads();
|
downloadManager.resumeDownloads();
|
||||||
downloadManagerHelper =
|
downloadManagerHelper =
|
||||||
new DownloadManagerHelper(
|
new DownloadManagerHelper(
|
||||||
getApplicationContext(), downloadManager, foregroundAllowed, scheduler, clazz);
|
getApplicationContext(), downloadManager, foregroundAllowed, scheduler, clazz);
|
||||||
downloadManagerHelpers.put(clazz, downloadManagerHelper);
|
downloadManagerHelpers.put(clazz, downloadManagerHelper);
|
||||||
} else {
|
|
||||||
if (downloadManagerHelper.scheduler != null) {
|
|
||||||
scheduler = downloadManagerHelper.scheduler;
|
|
||||||
}
|
|
||||||
downloadManager = downloadManagerHelper.downloadManager;
|
|
||||||
}
|
}
|
||||||
|
this.downloadManagerHelper = downloadManagerHelper;
|
||||||
downloadManagerHelper.attachService(this);
|
downloadManagerHelper.attachService(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,7 +615,8 @@ public abstract class DownloadService extends Service {
|
|||||||
if (intentAction == null) {
|
if (intentAction == null) {
|
||||||
intentAction = ACTION_INIT;
|
intentAction = ACTION_INIT;
|
||||||
}
|
}
|
||||||
DownloadManager downloadManager = Assertions.checkNotNull(this.downloadManager);
|
DownloadManager downloadManager =
|
||||||
|
Assertions.checkNotNull(downloadManagerHelper).downloadManager;
|
||||||
switch (intentAction) {
|
switch (intentAction) {
|
||||||
case ACTION_INIT:
|
case ACTION_INIT:
|
||||||
case ACTION_RESTART:
|
case ACTION_RESTART:
|
||||||
@ -666,21 +664,6 @@ public abstract class DownloadService extends Service {
|
|||||||
if (requirements == null) {
|
if (requirements == null) {
|
||||||
Log.e(TAG, "Ignored SET_REQUIREMENTS: Missing " + KEY_REQUIREMENTS + " extra");
|
Log.e(TAG, "Ignored SET_REQUIREMENTS: Missing " + KEY_REQUIREMENTS + " extra");
|
||||||
} else {
|
} else {
|
||||||
if (scheduler != null) {
|
|
||||||
Requirements supportedRequirements = scheduler.getSupportedRequirements(requirements);
|
|
||||||
if (!supportedRequirements.equals(requirements)) {
|
|
||||||
Log.w(
|
|
||||||
TAG,
|
|
||||||
"Ignoring requirements not supported by the Scheduler: "
|
|
||||||
+ (requirements.getRequirements() ^ supportedRequirements.getRequirements()));
|
|
||||||
// We need to make sure DownloadManager only uses requirements supported by the
|
|
||||||
// Scheduler. If we don't do this, DownloadManager can report itself as idle due to an
|
|
||||||
// unmet requirement that the Scheduler doesn't support. This can then lead to the
|
|
||||||
// service being destroyed, even though the Scheduler won't be able to restart it when
|
|
||||||
// the requirement is subsequently met.
|
|
||||||
requirements = supportedRequirements;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
downloadManager.setRequirements(requirements);
|
downloadManager.setRequirements(requirements);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -696,7 +679,7 @@ public abstract class DownloadService extends Service {
|
|||||||
|
|
||||||
isStopped = false;
|
isStopped = false;
|
||||||
if (downloadManager.isIdle()) {
|
if (downloadManager.isIdle()) {
|
||||||
stop();
|
onIdle();
|
||||||
}
|
}
|
||||||
return START_STICKY;
|
return START_STICKY;
|
||||||
}
|
}
|
||||||
@ -709,9 +692,7 @@ public abstract class DownloadService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
isDestroyed = true;
|
isDestroyed = true;
|
||||||
DownloadManagerHelper downloadManagerHelper =
|
Assertions.checkNotNull(downloadManagerHelper).detachService(this);
|
||||||
Assertions.checkNotNull(downloadManagerHelpers.get(getClass()));
|
|
||||||
downloadManagerHelper.detachService(this);
|
|
||||||
if (foregroundNotificationUpdater != null) {
|
if (foregroundNotificationUpdater != null) {
|
||||||
foregroundNotificationUpdater.stopPeriodicUpdates();
|
foregroundNotificationUpdater.stopPeriodicUpdates();
|
||||||
}
|
}
|
||||||
@ -733,14 +714,35 @@ public abstract class DownloadService extends Service {
|
|||||||
protected abstract DownloadManager getDownloadManager();
|
protected abstract DownloadManager getDownloadManager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link Scheduler} to restart the service when requirements allowing downloads to take
|
* Returns a {@link Scheduler} to restart the service when requirements for downloads to continue
|
||||||
* place are met. If {@code null}, the service will only be restarted if the process is still in
|
* are met.
|
||||||
* memory when the requirements are met.
|
|
||||||
*
|
*
|
||||||
* <p>This method is not called for services whose {@code foregroundNotificationId} is set to
|
* <p>This method is not called on all devices or for all service configurations. When it is
|
||||||
* {@link #FOREGROUND_NOTIFICATION_ID_NONE}. Such services will only be restarted if the process
|
* called, it's called only once in the life cycle of the process. If a service has unfinished
|
||||||
* is still in memory and considered non-idle, meaning that it's either in the foreground or was
|
* downloads that cannot make progress due to unmet requirements, it will behave according to the
|
||||||
* backgrounded within the last few minutes.
|
* first matching case below:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>If the service has {@code foregroundNotificationId} set to {@link
|
||||||
|
* #FOREGROUND_NOTIFICATION_ID_NONE}, then this method will not be called. The service will
|
||||||
|
* remain in the background until the downloads are able to continue to completion or the
|
||||||
|
* service is killed by the platform.
|
||||||
|
* <li>If the device API level is less than 31, a {@link Scheduler} is returned from this
|
||||||
|
* method, and the returned {@link Scheduler} {@link Scheduler#getSupportedRequirements
|
||||||
|
* supports} all of the requirements that have been specified for downloads to continue,
|
||||||
|
* then the service will stop itself and the {@link Scheduler} will be used to restart it in
|
||||||
|
* the foreground when the requirements are met.
|
||||||
|
* <li>If the device API level is less than 31 and either {@code null} or a {@link Scheduler}
|
||||||
|
* that does not {@link Scheduler#getSupportedRequirements support} all of the requirements
|
||||||
|
* is returned from this method, then the service will remain in the foreground until the
|
||||||
|
* downloads are able to continue to completion.
|
||||||
|
* <li>If the device API level is 31 or above, then this method will not be called and the
|
||||||
|
* service will remain in the foreground until the downloads are able to continue to
|
||||||
|
* completion. A {@link Scheduler} cannot be used for this case due to <a
|
||||||
|
* href="https://developer.android.com/about/versions/12/foreground-services">Android 12
|
||||||
|
* foreground service launch restrictions</a>.
|
||||||
|
* <li>
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
protected abstract Scheduler getScheduler();
|
protected abstract Scheduler getScheduler();
|
||||||
@ -758,7 +760,7 @@ public abstract class DownloadService extends Service {
|
|||||||
* @return The foreground notification to display.
|
* @return The foreground notification to display.
|
||||||
*/
|
*/
|
||||||
protected abstract Notification getForegroundNotification(
|
protected abstract Notification getForegroundNotification(
|
||||||
List<Download> downloads, @Requirements.RequirementFlags int notMetRequirements);
|
List<Download> downloads, @RequirementFlags int notMetRequirements);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalidates the current foreground notification and causes {@link
|
* Invalidates the current foreground notification and causes {@link
|
||||||
@ -813,10 +815,21 @@ public abstract class DownloadService extends Service {
|
|||||||
return isStopped;
|
return isStopped;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stop() {
|
private void onIdle() {
|
||||||
if (foregroundNotificationUpdater != null) {
|
if (foregroundNotificationUpdater != null) {
|
||||||
|
// Whether the service remains started or not, we don't need periodic notification updates
|
||||||
|
// when the DownloadManager is idle.
|
||||||
foregroundNotificationUpdater.stopPeriodicUpdates();
|
foregroundNotificationUpdater.stopPeriodicUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Assertions.checkNotNull(downloadManagerHelper).updateScheduler()) {
|
||||||
|
// We failed to schedule the service to restart when requirements that the DownloadManager is
|
||||||
|
// waiting for are met, so remain started.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the service, either because the DownloadManager is not waiting for requirements to be
|
||||||
|
// met, or because we've scheduled the service to be restarted when they are.
|
||||||
if (Util.SDK_INT < 28 && taskRemoved) { // See [Internal: b/74248644].
|
if (Util.SDK_INT < 28 && taskRemoved) { // See [Internal: b/74248644].
|
||||||
stopSelf();
|
stopSelf();
|
||||||
isStopped = true;
|
isStopped = true;
|
||||||
@ -887,9 +900,10 @@ public abstract class DownloadService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void update() {
|
private void update() {
|
||||||
List<Download> downloads = Assertions.checkNotNull(downloadManager).getCurrentDownloads();
|
DownloadManager downloadManager =
|
||||||
@Requirements.RequirementFlags
|
Assertions.checkNotNull(downloadManagerHelper).downloadManager;
|
||||||
int notMetRequirements = downloadManager.getNotMetRequirements();
|
List<Download> downloads = downloadManager.getCurrentDownloads();
|
||||||
|
@RequirementFlags int notMetRequirements = downloadManager.getNotMetRequirements();
|
||||||
Notification notification = getForegroundNotification(downloads, notMetRequirements);
|
Notification notification = getForegroundNotification(downloads, notMetRequirements);
|
||||||
if (!notificationDisplayed) {
|
if (!notificationDisplayed) {
|
||||||
startForeground(notificationId, notification);
|
startForeground(notificationId, notification);
|
||||||
@ -914,7 +928,9 @@ public abstract class DownloadService extends Service {
|
|||||||
private final boolean foregroundAllowed;
|
private final boolean foregroundAllowed;
|
||||||
@Nullable private final Scheduler scheduler;
|
@Nullable private final Scheduler scheduler;
|
||||||
private final Class<? extends DownloadService> serviceClass;
|
private final Class<? extends DownloadService> serviceClass;
|
||||||
|
|
||||||
@Nullable private DownloadService downloadService;
|
@Nullable private DownloadService downloadService;
|
||||||
|
private @MonotonicNonNull Requirements scheduledRequirements;
|
||||||
|
|
||||||
private DownloadManagerHelper(
|
private DownloadManagerHelper(
|
||||||
Context context,
|
Context context,
|
||||||
@ -949,8 +965,46 @@ public abstract class DownloadService extends Service {
|
|||||||
public void detachService(DownloadService downloadService) {
|
public void detachService(DownloadService downloadService) {
|
||||||
Assertions.checkState(this.downloadService == downloadService);
|
Assertions.checkState(this.downloadService == downloadService);
|
||||||
this.downloadService = null;
|
this.downloadService = null;
|
||||||
if (scheduler != null && !downloadManager.isWaitingForRequirements()) {
|
}
|
||||||
scheduler.cancel();
|
|
||||||
|
/**
|
||||||
|
* Schedules or cancels restarting the service, as needed for the current state.
|
||||||
|
*
|
||||||
|
* @return True if the DownloadManager is not waiting for requirements, or if it is waiting for
|
||||||
|
* requirements and the service has been successfully scheduled to be restarted when they
|
||||||
|
* are met. False if the DownloadManager is waiting for requirements and the service has not
|
||||||
|
* been scheduled for restart.
|
||||||
|
*/
|
||||||
|
public boolean updateScheduler() {
|
||||||
|
boolean waitingForRequirements = downloadManager.isWaitingForRequirements();
|
||||||
|
if (scheduler == null) {
|
||||||
|
return !waitingForRequirements;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!waitingForRequirements) {
|
||||||
|
cancelScheduler();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Requirements requirements = downloadManager.getRequirements();
|
||||||
|
Requirements supportedRequirements = scheduler.getSupportedRequirements(requirements);
|
||||||
|
if (!supportedRequirements.equals(requirements)) {
|
||||||
|
cancelScheduler();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!schedulerNeedsUpdate(requirements)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
String servicePackage = context.getPackageName();
|
||||||
|
if (scheduler.schedule(requirements, servicePackage, ACTION_RESTART)) {
|
||||||
|
scheduledRequirements = requirements;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Failed to schedule restart");
|
||||||
|
cancelScheduler();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -989,10 +1043,18 @@ public abstract class DownloadService extends Service {
|
|||||||
@Override
|
@Override
|
||||||
public final void onIdle(DownloadManager downloadManager) {
|
public final void onIdle(DownloadManager downloadManager) {
|
||||||
if (downloadService != null) {
|
if (downloadService != null) {
|
||||||
downloadService.stop();
|
downloadService.onIdle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequirementsStateChanged(
|
||||||
|
DownloadManager downloadManager,
|
||||||
|
Requirements requirements,
|
||||||
|
@RequirementFlags int notMetRequirements) {
|
||||||
|
updateScheduler();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onWaitingForRequirementsChanged(
|
public void onWaitingForRequirementsChanged(
|
||||||
DownloadManager downloadManager, boolean waitingForRequirements) {
|
DownloadManager downloadManager, boolean waitingForRequirements) {
|
||||||
@ -1006,23 +1068,42 @@ public abstract class DownloadService extends Service {
|
|||||||
for (int i = 0; i < downloads.size(); i++) {
|
for (int i = 0; i < downloads.size(); i++) {
|
||||||
if (downloads.get(i).state == Download.STATE_QUEUED) {
|
if (downloads.get(i).state == Download.STATE_QUEUED) {
|
||||||
restartService();
|
restartService();
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
updateScheduler();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
|
private boolean schedulerNeedsUpdate(Requirements requirements) {
|
||||||
|
return !Util.areEqual(scheduledRequirements, requirements);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresNonNull("scheduler")
|
||||||
|
private void cancelScheduler() {
|
||||||
|
Requirements canceledRequirements = new Requirements(/* requirements= */ 0);
|
||||||
|
if (schedulerNeedsUpdate(canceledRequirements)) {
|
||||||
|
scheduler.cancel();
|
||||||
|
scheduledRequirements = canceledRequirements;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private boolean serviceMayNeedRestart() {
|
private boolean serviceMayNeedRestart() {
|
||||||
return downloadService == null || downloadService.isStopped();
|
return downloadService == null || downloadService.isStopped();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restartService() {
|
private void restartService() {
|
||||||
if (foregroundAllowed) {
|
if (foregroundAllowed) {
|
||||||
|
try {
|
||||||
Intent intent = getIntent(context, serviceClass, DownloadService.ACTION_RESTART);
|
Intent intent = getIntent(context, serviceClass, DownloadService.ACTION_RESTART);
|
||||||
Util.startForegroundService(context, intent);
|
Util.startForegroundService(context, intent);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
// The process is running in the background, and is not allowed to start a foreground
|
||||||
|
// service due to foreground service launch restrictions
|
||||||
|
// (https://developer.android.com/about/versions/12/foreground-services).
|
||||||
|
Log.w(TAG, "Failed to restart (foreground launch restriction)");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// The service is background only. Use ACTION_INIT rather than ACTION_RESTART because
|
// The service is background only. Use ACTION_INIT rather than ACTION_RESTART because
|
||||||
// ACTION_RESTART is handled as though KEY_FOREGROUND is set to true.
|
// ACTION_RESTART is handled as though KEY_FOREGROUND is set to true.
|
||||||
@ -1032,24 +1113,8 @@ public abstract class DownloadService extends Service {
|
|||||||
} catch (IllegalStateException e) {
|
} catch (IllegalStateException e) {
|
||||||
// The process is classed as idle by the platform. Starting a background service is not
|
// The process is classed as idle by the platform. Starting a background service is not
|
||||||
// allowed in this state.
|
// allowed in this state.
|
||||||
Log.w(TAG, "Failed to restart DownloadService (process is idle).");
|
Log.w(TAG, "Failed to restart (process is idle)");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateScheduler() {
|
|
||||||
if (scheduler == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (downloadManager.isWaitingForRequirements()) {
|
|
||||||
String servicePackage = context.getPackageName();
|
|
||||||
Requirements requirements = downloadManager.getRequirements();
|
|
||||||
boolean success = scheduler.schedule(requirements, servicePackage, ACTION_RESTART);
|
|
||||||
if (!success) {
|
|
||||||
Log.e(TAG, "Scheduling downloads failed.");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
scheduler.cancel();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user