mirror of
https://github.com/androidx/media.git
synced 2025-05-11 01:31:40 +08:00
Merge pull request #7395 from jdegroot-dss:add-storage-not-low-requirement
PiperOrigin-RevId: 313804207
This commit is contained in:
commit
496a315d91
@ -142,6 +142,8 @@
|
||||
directly instead.
|
||||
* Update `CachedContentIndex` to use `SecureRandom` for generating the
|
||||
initialization vector used to encrypt the cache contents.
|
||||
* Add `Requirements.DEVICE_STORAGE_NOT_LOW`, which can be specified as a
|
||||
requirement to a `DownloadManager` for it to proceed with downloading.
|
||||
* Audio:
|
||||
* Add a sample count parameter to `MediaCodecRenderer.processOutputBuffer`
|
||||
and `AudioSink.handleBuffer` to allow batching multiple encoded frames
|
||||
|
@ -65,6 +65,11 @@ public final class JobDispatcherScheduler implements Scheduler {
|
||||
private static final String KEY_SERVICE_ACTION = "service_action";
|
||||
private static final String KEY_SERVICE_PACKAGE = "service_package";
|
||||
private static final String KEY_REQUIREMENTS = "requirements";
|
||||
private static final int SUPPORTED_REQUIREMENTS =
|
||||
Requirements.NETWORK
|
||||
| Requirements.NETWORK_UNMETERED
|
||||
| Requirements.DEVICE_IDLE
|
||||
| Requirements.DEVICE_CHARGING;
|
||||
|
||||
private final String jobTag;
|
||||
private final FirebaseJobDispatcher jobDispatcher;
|
||||
@ -96,24 +101,35 @@ public final class JobDispatcherScheduler implements Scheduler {
|
||||
return result == FirebaseJobDispatcher.CANCEL_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requirements getSupportedRequirements(Requirements requirements) {
|
||||
return requirements.filterRequirements(SUPPORTED_REQUIREMENTS);
|
||||
}
|
||||
|
||||
private static Job buildJob(
|
||||
FirebaseJobDispatcher dispatcher,
|
||||
Requirements requirements,
|
||||
String tag,
|
||||
String servicePackage,
|
||||
String serviceAction) {
|
||||
Requirements filteredRequirements = requirements.filterRequirements(SUPPORTED_REQUIREMENTS);
|
||||
if (!filteredRequirements.equals(requirements)) {
|
||||
Log.w(
|
||||
TAG,
|
||||
"Ignoring unsupported requirements: "
|
||||
+ (filteredRequirements.getRequirements() ^ requirements.getRequirements()));
|
||||
}
|
||||
|
||||
Job.Builder builder =
|
||||
dispatcher
|
||||
.newJobBuilder()
|
||||
.setService(JobDispatcherSchedulerService.class) // the JobService that will be called
|
||||
.setTag(tag);
|
||||
|
||||
if (requirements.isUnmeteredNetworkRequired()) {
|
||||
builder.addConstraint(Constraint.ON_UNMETERED_NETWORK);
|
||||
} else if (requirements.isNetworkRequired()) {
|
||||
builder.addConstraint(Constraint.ON_ANY_NETWORK);
|
||||
}
|
||||
|
||||
if (requirements.isIdleRequired()) {
|
||||
builder.addConstraint(Constraint.DEVICE_IDLE);
|
||||
}
|
||||
|
@ -40,6 +40,12 @@ public final class WorkManagerScheduler implements Scheduler {
|
||||
private static final String KEY_SERVICE_ACTION = "service_action";
|
||||
private static final String KEY_SERVICE_PACKAGE = "service_package";
|
||||
private static final String KEY_REQUIREMENTS = "requirements";
|
||||
private static final int SUPPORTED_REQUIREMENTS =
|
||||
Requirements.NETWORK
|
||||
| Requirements.NETWORK_UNMETERED
|
||||
| (Util.SDK_INT >= 23 ? Requirements.DEVICE_IDLE : 0)
|
||||
| Requirements.DEVICE_CHARGING
|
||||
| Requirements.DEVICE_STORAGE_NOT_LOW;
|
||||
|
||||
private final String workName;
|
||||
|
||||
@ -70,9 +76,21 @@ public final class WorkManagerScheduler implements Scheduler {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Constraints buildConstraints(Requirements requirements) {
|
||||
Constraints.Builder builder = new Constraints.Builder();
|
||||
@Override
|
||||
public Requirements getSupportedRequirements(Requirements requirements) {
|
||||
return requirements.filterRequirements(SUPPORTED_REQUIREMENTS);
|
||||
}
|
||||
|
||||
private static Constraints buildConstraints(Requirements requirements) {
|
||||
Requirements filteredRequirements = requirements.filterRequirements(SUPPORTED_REQUIREMENTS);
|
||||
if (!filteredRequirements.equals(requirements)) {
|
||||
Log.w(
|
||||
TAG,
|
||||
"Ignoring unsupported requirements: "
|
||||
+ (filteredRequirements.getRequirements() ^ requirements.getRequirements()));
|
||||
}
|
||||
|
||||
Constraints.Builder builder = new Constraints.Builder();
|
||||
if (requirements.isUnmeteredNetworkRequired()) {
|
||||
builder.setRequiredNetworkType(NetworkType.UNMETERED);
|
||||
} else if (requirements.isNetworkRequired()) {
|
||||
@ -80,13 +98,14 @@ public final class WorkManagerScheduler implements Scheduler {
|
||||
} else {
|
||||
builder.setRequiredNetworkType(NetworkType.NOT_REQUIRED);
|
||||
}
|
||||
|
||||
if (Util.SDK_INT >= 23 && requirements.isIdleRequired()) {
|
||||
setRequiresDeviceIdle(builder);
|
||||
}
|
||||
if (requirements.isChargingRequired()) {
|
||||
builder.setRequiresCharging(true);
|
||||
}
|
||||
|
||||
if (requirements.isIdleRequired() && Util.SDK_INT >= 23) {
|
||||
setRequiresDeviceIdle(builder);
|
||||
if (requirements.isStorageNotLowRequired()) {
|
||||
builder.setRequiresStorageNotLow(true);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
|
@ -658,6 +658,22 @@ public abstract class DownloadService extends Service {
|
||||
if (requirements == null) {
|
||||
Log.e(TAG, "Ignored SET_REQUIREMENTS: Missing " + KEY_REQUIREMENTS + " extra");
|
||||
} else {
|
||||
@Nullable Scheduler scheduler = getScheduler();
|
||||
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);
|
||||
}
|
||||
break;
|
||||
|
@ -50,6 +50,12 @@ public final class PlatformScheduler implements Scheduler {
|
||||
private static final String KEY_SERVICE_ACTION = "service_action";
|
||||
private static final String KEY_SERVICE_PACKAGE = "service_package";
|
||||
private static final String KEY_REQUIREMENTS = "requirements";
|
||||
private static final int SUPPORTED_REQUIREMENTS =
|
||||
Requirements.NETWORK
|
||||
| Requirements.NETWORK_UNMETERED
|
||||
| Requirements.DEVICE_IDLE
|
||||
| Requirements.DEVICE_CHARGING
|
||||
| (Util.SDK_INT >= 26 ? Requirements.DEVICE_STORAGE_NOT_LOW : 0);
|
||||
|
||||
private final int jobId;
|
||||
private final ComponentName jobServiceComponentName;
|
||||
@ -86,6 +92,11 @@ public final class PlatformScheduler implements Scheduler {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Requirements getSupportedRequirements(Requirements requirements) {
|
||||
return requirements.filterRequirements(SUPPORTED_REQUIREMENTS);
|
||||
}
|
||||
|
||||
// @RequiresPermission constructor annotation should ensure the permission is present.
|
||||
@SuppressWarnings("MissingPermission")
|
||||
private static JobInfo buildJobInfo(
|
||||
@ -94,8 +105,15 @@ public final class PlatformScheduler implements Scheduler {
|
||||
Requirements requirements,
|
||||
String serviceAction,
|
||||
String servicePackage) {
|
||||
JobInfo.Builder builder = new JobInfo.Builder(jobId, jobServiceComponentName);
|
||||
Requirements filteredRequirements = requirements.filterRequirements(SUPPORTED_REQUIREMENTS);
|
||||
if (!filteredRequirements.equals(requirements)) {
|
||||
Log.w(
|
||||
TAG,
|
||||
"Ignoring unsupported requirements: "
|
||||
+ (filteredRequirements.getRequirements() ^ requirements.getRequirements()));
|
||||
}
|
||||
|
||||
JobInfo.Builder builder = new JobInfo.Builder(jobId, jobServiceComponentName);
|
||||
if (requirements.isUnmeteredNetworkRequired()) {
|
||||
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
|
||||
} else if (requirements.isNetworkRequired()) {
|
||||
@ -103,6 +121,9 @@ public final class PlatformScheduler implements Scheduler {
|
||||
}
|
||||
builder.setRequiresDeviceIdle(requirements.isIdleRequired());
|
||||
builder.setRequiresCharging(requirements.isChargingRequired());
|
||||
if (Util.SDK_INT >= 26 && requirements.isStorageNotLowRequired()) {
|
||||
builder.setRequiresStorageNotLow(true);
|
||||
}
|
||||
builder.setPersisted(true);
|
||||
|
||||
PersistableBundle extras = new PersistableBundle();
|
||||
|
@ -39,13 +39,13 @@ public final class Requirements implements Parcelable {
|
||||
|
||||
/**
|
||||
* Requirement flags. Possible flag values are {@link #NETWORK}, {@link #NETWORK_UNMETERED},
|
||||
* {@link #DEVICE_IDLE} and {@link #DEVICE_CHARGING}.
|
||||
* {@link #DEVICE_IDLE}, {@link #DEVICE_CHARGING} and {@link #DEVICE_STORAGE_NOT_LOW}.
|
||||
*/
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef(
|
||||
flag = true,
|
||||
value = {NETWORK, NETWORK_UNMETERED, DEVICE_IDLE, DEVICE_CHARGING})
|
||||
value = {NETWORK, NETWORK_UNMETERED, DEVICE_IDLE, DEVICE_CHARGING, DEVICE_STORAGE_NOT_LOW})
|
||||
public @interface RequirementFlags {}
|
||||
|
||||
/** Requirement that the device has network connectivity. */
|
||||
@ -56,6 +56,11 @@ public final class Requirements implements Parcelable {
|
||||
public static final int DEVICE_IDLE = 1 << 2;
|
||||
/** Requirement that the device is charging. */
|
||||
public static final int DEVICE_CHARGING = 1 << 3;
|
||||
/**
|
||||
* Requirement that the device's <em>internal</em> storage is not low. Note that this requirement
|
||||
* is not affected by the status of external storage.
|
||||
*/
|
||||
public static final int DEVICE_STORAGE_NOT_LOW = 1 << 4;
|
||||
|
||||
@RequirementFlags private final int requirements;
|
||||
|
||||
@ -74,6 +79,18 @@ public final class Requirements implements Parcelable {
|
||||
return requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the requirements, returning the subset that are enabled by the provided filter.
|
||||
*
|
||||
* @param requirementsFilter The enabled {@link RequirementFlags}.
|
||||
* @return The filtered requirements. If the filter does not cause a change in the requirements
|
||||
* then this instance will be returned.
|
||||
*/
|
||||
public Requirements filterRequirements(int requirementsFilter) {
|
||||
int filteredRequirements = requirements & requirementsFilter;
|
||||
return filteredRequirements == requirements ? this : new Requirements(filteredRequirements);
|
||||
}
|
||||
|
||||
/** Returns whether network connectivity is required. */
|
||||
public boolean isNetworkRequired() {
|
||||
return (requirements & NETWORK) != 0;
|
||||
@ -94,6 +111,11 @@ public final class Requirements implements Parcelable {
|
||||
return (requirements & DEVICE_IDLE) != 0;
|
||||
}
|
||||
|
||||
/** Returns whether the device is required to not be low on <em>internal</em> storage. */
|
||||
public boolean isStorageNotLowRequired() {
|
||||
return (requirements & DEVICE_STORAGE_NOT_LOW) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the requirements are met.
|
||||
*
|
||||
@ -119,6 +141,9 @@ public final class Requirements implements Parcelable {
|
||||
if (isIdleRequired() && !isDeviceIdle(context)) {
|
||||
notMetRequirements |= DEVICE_IDLE;
|
||||
}
|
||||
if (isStorageNotLowRequired() && !isStorageNotLow(context)) {
|
||||
notMetRequirements |= DEVICE_STORAGE_NOT_LOW;
|
||||
}
|
||||
return notMetRequirements;
|
||||
}
|
||||
|
||||
@ -145,8 +170,10 @@ public final class Requirements implements Parcelable {
|
||||
}
|
||||
|
||||
private boolean isDeviceCharging(Context context) {
|
||||
@Nullable
|
||||
Intent batteryStatus =
|
||||
context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
context.registerReceiver(
|
||||
/* receiver= */ null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
if (batteryStatus == null) {
|
||||
return false;
|
||||
}
|
||||
@ -162,6 +189,12 @@ public final class Requirements implements Parcelable {
|
||||
: Util.SDK_INT >= 20 ? !powerManager.isInteractive() : !powerManager.isScreenOn();
|
||||
}
|
||||
|
||||
private boolean isStorageNotLow(Context context) {
|
||||
return context.registerReceiver(
|
||||
/* receiver= */ null, new IntentFilter(Intent.ACTION_DEVICE_STORAGE_LOW))
|
||||
== null;
|
||||
}
|
||||
|
||||
private static boolean isInternetConnectivityValidated(ConnectivityManager connectivityManager) {
|
||||
// It's possible to query NetworkCapabilities from API level 23, but RequirementsWatcher only
|
||||
// fires an event to update its Requirements when NetworkCapabilities change from API level 24.
|
||||
|
@ -104,6 +104,10 @@ public final class RequirementsWatcher {
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
}
|
||||
}
|
||||
if (requirements.isStorageNotLowRequired()) {
|
||||
filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
|
||||
filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
|
||||
}
|
||||
receiver = new DeviceStatusChangeReceiver();
|
||||
context.registerReceiver(receiver, filter, null, handler);
|
||||
return notMetRequirements;
|
||||
|
@ -45,4 +45,14 @@ public interface Scheduler {
|
||||
* @return Whether cancellation was successful.
|
||||
*/
|
||||
boolean cancel();
|
||||
|
||||
/**
|
||||
* Checks whether this {@link Scheduler} supports the provided {@link Requirements}. If all of the
|
||||
* requirements are supported then the same {@link Requirements} instance is returned. If not then
|
||||
* a new instance is returned containing the subset of the requirements that are supported.
|
||||
*
|
||||
* @param requirements The requirements to check.
|
||||
* @return The supported requirements.
|
||||
*/
|
||||
Requirements getSupportedRequirements(Requirements requirements);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user