Commit 3f565c33 by olly Committed by Oliver Woodman

Simplify offline Requirements

- Remove NETWORK_TYPE_NOT_ROAMING and NETWORK_TYPE_METERED
  because JobScheduler doesn't support them, and they're
  probably not useful to many people (data when roaming is
  normally enabled/disabled at the OS level, and restricting
  to *only* metered networks seems niche)
- Convert network requirements proper flags
- Stop persisting requirements in DownloadIndex. The direction
  we're headed to solve the manager start/stop problem is
  going to involve state in DownloadManager determining whether
  downloads actually start, and if we're doing that then it's
  no worse to do it for this as well

PiperOrigin-RevId: 242713196
parent 9e6f9ee9
...@@ -104,18 +104,10 @@ public final class JobDispatcherScheduler implements Scheduler { ...@@ -104,18 +104,10 @@ public final class JobDispatcherScheduler implements Scheduler {
.setService(JobDispatcherSchedulerService.class) // the JobService that will be called .setService(JobDispatcherSchedulerService.class) // the JobService that will be called
.setTag(tag); .setTag(tag);
switch (requirements.getRequiredNetworkType()) { if (requirements.isUnmeteredNetworkRequired()) {
case Requirements.NETWORK_TYPE_NONE: builder.addConstraint(Constraint.ON_UNMETERED_NETWORK);
// do nothing. } else if (requirements.isNetworkRequired()) {
break; builder.addConstraint(Constraint.ON_ANY_NETWORK);
case Requirements.NETWORK_TYPE_ANY:
builder.addConstraint(Constraint.ON_ANY_NETWORK);
break;
case Requirements.NETWORK_TYPE_UNMETERED:
builder.addConstraint(Constraint.ON_UNMETERED_NETWORK);
break;
default:
throw new UnsupportedOperationException();
} }
if (requirements.isIdleRequired()) { if (requirements.isIdleRequired()) {
......
...@@ -57,15 +57,20 @@ public final class DefaultDownloadIndex implements DownloadIndex { ...@@ -57,15 +57,20 @@ public final class DefaultDownloadIndex implements DownloadIndex {
private static final String COLUMN_DOWNLOADED_BYTES = "downloaded_bytes"; private static final String COLUMN_DOWNLOADED_BYTES = "downloaded_bytes";
private static final String COLUMN_TOTAL_BYTES = "total_bytes"; private static final String COLUMN_TOTAL_BYTES = "total_bytes";
private static final String COLUMN_FAILURE_REASON = "failure_reason"; private static final String COLUMN_FAILURE_REASON = "failure_reason";
private static final String COLUMN_NOT_MET_REQUIREMENTS = "not_met_requirements";
private static final String COLUMN_MANUAL_STOP_REASON = "manual_stop_reason"; private static final String COLUMN_MANUAL_STOP_REASON = "manual_stop_reason";
private static final String COLUMN_START_TIME_MS = "start_time_ms"; private static final String COLUMN_START_TIME_MS = "start_time_ms";
private static final String COLUMN_UPDATE_TIME_MS = "update_time_ms"; private static final String COLUMN_UPDATE_TIME_MS = "update_time_ms";
/** @deprecated No longer used. */
@SuppressWarnings("DeprecatedIsStillUsed") @SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated @Deprecated
private static final String COLUMN_STOP_FLAGS = "stop_flags"; private static final String COLUMN_STOP_FLAGS = "stop_flags";
/** @deprecated No longer used. */
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
private static final String COLUMN_NOT_MET_REQUIREMENTS = "not_met_requirements";
private static final int COLUMN_INDEX_ID = 0; private static final int COLUMN_INDEX_ID = 0;
private static final int COLUMN_INDEX_TYPE = 1; private static final int COLUMN_INDEX_TYPE = 1;
private static final int COLUMN_INDEX_URI = 2; private static final int COLUMN_INDEX_URI = 2;
...@@ -77,10 +82,9 @@ public final class DefaultDownloadIndex implements DownloadIndex { ...@@ -77,10 +82,9 @@ public final class DefaultDownloadIndex implements DownloadIndex {
private static final int COLUMN_INDEX_DOWNLOADED_BYTES = 8; private static final int COLUMN_INDEX_DOWNLOADED_BYTES = 8;
private static final int COLUMN_INDEX_TOTAL_BYTES = 9; private static final int COLUMN_INDEX_TOTAL_BYTES = 9;
private static final int COLUMN_INDEX_FAILURE_REASON = 10; private static final int COLUMN_INDEX_FAILURE_REASON = 10;
private static final int COLUMN_INDEX_NOT_MET_REQUIREMENTS = 11; private static final int COLUMN_INDEX_MANUAL_STOP_REASON = 11;
private static final int COLUMN_INDEX_MANUAL_STOP_REASON = 12; private static final int COLUMN_INDEX_START_TIME_MS = 12;
private static final int COLUMN_INDEX_START_TIME_MS = 13; private static final int COLUMN_INDEX_UPDATE_TIME_MS = 13;
private static final int COLUMN_INDEX_UPDATE_TIME_MS = 14;
private static final String WHERE_ID_EQUALS = COLUMN_ID + " = ?"; private static final String WHERE_ID_EQUALS = COLUMN_ID + " = ?";
private static final String WHERE_STATE_TERMINAL = private static final String WHERE_STATE_TERMINAL =
...@@ -99,7 +103,6 @@ public final class DefaultDownloadIndex implements DownloadIndex { ...@@ -99,7 +103,6 @@ public final class DefaultDownloadIndex implements DownloadIndex {
COLUMN_DOWNLOADED_BYTES, COLUMN_DOWNLOADED_BYTES,
COLUMN_TOTAL_BYTES, COLUMN_TOTAL_BYTES,
COLUMN_FAILURE_REASON, COLUMN_FAILURE_REASON,
COLUMN_NOT_MET_REQUIREMENTS,
COLUMN_MANUAL_STOP_REASON, COLUMN_MANUAL_STOP_REASON,
COLUMN_START_TIME_MS, COLUMN_START_TIME_MS,
COLUMN_UPDATE_TIME_MS COLUMN_UPDATE_TIME_MS
...@@ -204,7 +207,7 @@ public final class DefaultDownloadIndex implements DownloadIndex { ...@@ -204,7 +207,7 @@ public final class DefaultDownloadIndex implements DownloadIndex {
values.put(COLUMN_TOTAL_BYTES, downloadState.getTotalBytes()); values.put(COLUMN_TOTAL_BYTES, downloadState.getTotalBytes());
values.put(COLUMN_FAILURE_REASON, downloadState.failureReason); values.put(COLUMN_FAILURE_REASON, downloadState.failureReason);
values.put(COLUMN_STOP_FLAGS, 0); values.put(COLUMN_STOP_FLAGS, 0);
values.put(COLUMN_NOT_MET_REQUIREMENTS, downloadState.notMetRequirements); values.put(COLUMN_NOT_MET_REQUIREMENTS, 0);
values.put(COLUMN_MANUAL_STOP_REASON, downloadState.manualStopReason); values.put(COLUMN_MANUAL_STOP_REASON, downloadState.manualStopReason);
values.put(COLUMN_START_TIME_MS, downloadState.startTimeMs); values.put(COLUMN_START_TIME_MS, downloadState.startTimeMs);
values.put(COLUMN_UPDATE_TIME_MS, downloadState.updateTimeMs); values.put(COLUMN_UPDATE_TIME_MS, downloadState.updateTimeMs);
...@@ -356,7 +359,6 @@ public final class DefaultDownloadIndex implements DownloadIndex { ...@@ -356,7 +359,6 @@ public final class DefaultDownloadIndex implements DownloadIndex {
action, action,
cursor.getInt(COLUMN_INDEX_STATE), cursor.getInt(COLUMN_INDEX_STATE),
cursor.getInt(COLUMN_INDEX_FAILURE_REASON), cursor.getInt(COLUMN_INDEX_FAILURE_REASON),
cursor.getInt(COLUMN_INDEX_NOT_MET_REQUIREMENTS),
cursor.getInt(COLUMN_INDEX_MANUAL_STOP_REASON), cursor.getInt(COLUMN_INDEX_MANUAL_STOP_REASON),
cursor.getLong(COLUMN_INDEX_START_TIME_MS), cursor.getLong(COLUMN_INDEX_START_TIME_MS),
cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS), cursor.getLong(COLUMN_INDEX_UPDATE_TIME_MS),
......
...@@ -71,7 +71,7 @@ public final class DownloadIndexUtil { ...@@ -71,7 +71,7 @@ public final class DownloadIndexUtil {
throws IOException { throws IOException {
DownloadState downloadState = downloadIndex.getDownloadState(action.id); DownloadState downloadState = downloadIndex.getDownloadState(action.id);
if (downloadState != null) { if (downloadState != null) {
downloadState = downloadState.copyWithMergedAction(action); downloadState = downloadState.copyWithMergedAction(action, /* canStart= */ true);
} else { } else {
downloadState = new DownloadState(action); downloadState = new DownloadState(action);
} }
......
...@@ -113,8 +113,7 @@ public final class DownloadManager { ...@@ -113,8 +113,7 @@ public final class DownloadManager {
/** The default minimum number of times a download must be retried before failing. */ /** The default minimum number of times a download must be retried before failing. */
public static final int DEFAULT_MIN_RETRY_COUNT = 5; public static final int DEFAULT_MIN_RETRY_COUNT = 5;
/** The default requirement is that the device has network connectivity. */ /** The default requirement is that the device has network connectivity. */
public static final Requirements DEFAULT_REQUIREMENTS = public static final Requirements DEFAULT_REQUIREMENTS = new Requirements(Requirements.NETWORK);
new Requirements(Requirements.NETWORK_TYPE_ANY, false, false);
// Messages posted to the main handler. // Messages posted to the main handler.
private static final int MSG_INITIALIZED = 0; private static final int MSG_INITIALIZED = 0;
...@@ -623,7 +622,8 @@ public final class DownloadManager { ...@@ -623,7 +622,8 @@ public final class DownloadManager {
downloadState = new DownloadState(action); downloadState = new DownloadState(action);
logd("Download state is created for " + action.id); logd("Download state is created for " + action.id);
} else { } else {
downloadState = downloadState.copyWithMergedAction(action); downloadState =
downloadState.copyWithMergedAction(action, /* canStart= */ notMetRequirements == 0);
logd("Download state is loaded for " + action.id); logd("Download state is loaded for " + action.id);
} }
addDownloadForState(downloadState); addDownloadForState(downloadState);
...@@ -840,7 +840,8 @@ public final class DownloadManager { ...@@ -840,7 +840,8 @@ public final class DownloadManager {
} }
public void addAction(DownloadAction newAction) { public void addAction(DownloadAction newAction) {
downloadState = downloadState.copyWithMergedAction(newAction); downloadState =
downloadState.copyWithMergedAction(newAction, /* canStart= */ notMetRequirements == 0);
initialize(); initialize();
} }
...@@ -854,7 +855,6 @@ public final class DownloadManager { ...@@ -854,7 +855,6 @@ public final class DownloadManager {
downloadState.action, downloadState.action,
state, state,
state != STATE_FAILED ? FAILURE_REASON_NONE : failureReason, state != STATE_FAILED ? FAILURE_REASON_NONE : failureReason,
notMetRequirements,
manualStopReason, manualStopReason,
downloadState.startTimeMs, downloadState.startTimeMs,
/* updateTimeMs= */ System.currentTimeMillis(), /* updateTimeMs= */ System.currentTimeMillis(),
......
...@@ -17,8 +17,6 @@ package com.google.android.exoplayer2.offline; ...@@ -17,8 +17,6 @@ package com.google.android.exoplayer2.offline;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.scheduler.Requirements;
import com.google.android.exoplayer2.scheduler.Requirements.RequirementFlags;
import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters; import com.google.android.exoplayer2.upstream.cache.CacheUtil.CachingCounters;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
...@@ -124,8 +122,6 @@ public final class DownloadState { ...@@ -124,8 +122,6 @@ public final class DownloadState {
* #FAILURE_REASON_NONE}. * #FAILURE_REASON_NONE}.
*/ */
@FailureReason public final int failureReason; @FailureReason public final int failureReason;
/** Not met requirements to download. */
@Requirements.RequirementFlags public final int notMetRequirements;
/** The manual stop reason. */ /** The manual stop reason. */
public final int manualStopReason; public final int manualStopReason;
...@@ -145,7 +141,6 @@ public final class DownloadState { ...@@ -145,7 +141,6 @@ public final class DownloadState {
action, action,
/* state= */ STATE_QUEUED, /* state= */ STATE_QUEUED,
FAILURE_REASON_NONE, FAILURE_REASON_NONE,
/* notMetRequirements= */ 0,
/* manualStopReason= */ 0, /* manualStopReason= */ 0,
/* startTimeMs= */ currentTimeMs, /* startTimeMs= */ currentTimeMs,
/* updateTimeMs= */ currentTimeMs, /* updateTimeMs= */ currentTimeMs,
...@@ -156,20 +151,18 @@ public final class DownloadState { ...@@ -156,20 +151,18 @@ public final class DownloadState {
DownloadAction action, DownloadAction action,
@State int state, @State int state,
@FailureReason int failureReason, @FailureReason int failureReason,
@RequirementFlags int notMetRequirements,
int manualStopReason, int manualStopReason,
long startTimeMs, long startTimeMs,
long updateTimeMs, long updateTimeMs,
CachingCounters counters) { CachingCounters counters) {
Assertions.checkNotNull(counters); Assertions.checkNotNull(counters);
Assertions.checkState((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED)); Assertions.checkState((failureReason == FAILURE_REASON_NONE) == (state != STATE_FAILED));
if (manualStopReason != 0 || notMetRequirements != 0) { if (manualStopReason != 0) {
Assertions.checkState(state != STATE_DOWNLOADING && state != STATE_QUEUED); Assertions.checkState(state != STATE_DOWNLOADING && state != STATE_QUEUED);
} }
this.action = action; this.action = action;
this.state = state; this.state = state;
this.failureReason = failureReason; this.failureReason = failureReason;
this.notMetRequirements = notMetRequirements;
this.manualStopReason = manualStopReason; this.manualStopReason = manualStopReason;
this.startTimeMs = startTimeMs; this.startTimeMs = startTimeMs;
this.updateTimeMs = updateTimeMs; this.updateTimeMs = updateTimeMs;
...@@ -181,14 +174,14 @@ public final class DownloadState { ...@@ -181,14 +174,14 @@ public final class DownloadState {
* must have the same id and type. * must have the same id and type.
* *
* @param newAction The {@link DownloadAction} to be merged. * @param newAction The {@link DownloadAction} to be merged.
* @param canStart Whether the download is eligible to be started.
* @return A new {@link DownloadState}. * @return A new {@link DownloadState}.
*/ */
public DownloadState copyWithMergedAction(DownloadAction newAction) { public DownloadState copyWithMergedAction(DownloadAction newAction, boolean canStart) {
return new DownloadState( return new DownloadState(
action.copyWithMergedAction(newAction), action.copyWithMergedAction(newAction),
getNextState(state, manualStopReason != 0 || notMetRequirements != 0), getNextState(state, canStart && manualStopReason == 0),
FAILURE_REASON_NONE, FAILURE_REASON_NONE,
notMetRequirements,
manualStopReason, manualStopReason,
startTimeMs, startTimeMs,
/* updateTimeMs= */ System.currentTimeMillis(), /* updateTimeMs= */ System.currentTimeMillis(),
...@@ -205,7 +198,6 @@ public final class DownloadState { ...@@ -205,7 +198,6 @@ public final class DownloadState {
action, action,
state, state,
FAILURE_REASON_NONE, FAILURE_REASON_NONE,
notMetRequirements,
manualStopReason, manualStopReason,
startTimeMs, startTimeMs,
/* updateTimeMs= */ System.currentTimeMillis(), /* updateTimeMs= */ System.currentTimeMillis(),
...@@ -240,13 +232,13 @@ public final class DownloadState { ...@@ -240,13 +232,13 @@ public final class DownloadState {
this.counters = counters; this.counters = counters;
} }
private static int getNextState(int currentState, boolean isStopped) { private static int getNextState(int currentState, boolean canStart) {
if (currentState == STATE_REMOVING || currentState == STATE_RESTARTING) { if (currentState == STATE_REMOVING || currentState == STATE_RESTARTING) {
return STATE_RESTARTING; return STATE_RESTARTING;
} else if (isStopped) { } else if (canStart) {
return STATE_STOPPED;
} else {
return STATE_QUEUED; return STATE_QUEUED;
} else {
return STATE_STOPPED;
} }
} }
} }
...@@ -93,36 +93,11 @@ public final class PlatformScheduler implements Scheduler { ...@@ -93,36 +93,11 @@ public final class PlatformScheduler implements Scheduler {
String servicePackage) { String servicePackage) {
JobInfo.Builder builder = new JobInfo.Builder(jobId, jobServiceComponentName); JobInfo.Builder builder = new JobInfo.Builder(jobId, jobServiceComponentName);
int networkType; if (requirements.isUnmeteredNetworkRequired()) {
switch (requirements.getRequiredNetworkType()) { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
case Requirements.NETWORK_TYPE_NONE: } else if (requirements.isNetworkRequired()) {
networkType = JobInfo.NETWORK_TYPE_NONE; builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
break;
case Requirements.NETWORK_TYPE_ANY:
networkType = JobInfo.NETWORK_TYPE_ANY;
break;
case Requirements.NETWORK_TYPE_UNMETERED:
networkType = JobInfo.NETWORK_TYPE_UNMETERED;
break;
case Requirements.NETWORK_TYPE_NOT_ROAMING:
if (Util.SDK_INT >= 24) {
networkType = JobInfo.NETWORK_TYPE_NOT_ROAMING;
} else {
throw new UnsupportedOperationException();
}
break;
case Requirements.NETWORK_TYPE_METERED:
if (Util.SDK_INT >= 26) {
networkType = JobInfo.NETWORK_TYPE_METERED;
} else {
throw new UnsupportedOperationException();
}
break;
default:
throw new UnsupportedOperationException();
} }
builder.setRequiredNetworkType(networkType);
builder.setRequiresDeviceIdle(requirements.isIdleRequired()); builder.setRequiresDeviceIdle(requirements.isIdleRequired());
builder.setRequiresCharging(requirements.isChargingRequired()); builder.setRequiresCharging(requirements.isChargingRequired());
builder.setPersisted(true); builder.setPersisted(true);
......
...@@ -25,7 +25,6 @@ import android.net.NetworkInfo; ...@@ -25,7 +25,6 @@ import android.net.NetworkInfo;
import android.os.BatteryManager; import android.os.BatteryManager;
import android.os.PowerManager; import android.os.PowerManager;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Log; import com.google.android.exoplayer2.util.Log;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
...@@ -38,112 +37,60 @@ import java.lang.annotation.RetentionPolicy; ...@@ -38,112 +37,60 @@ import java.lang.annotation.RetentionPolicy;
public final class Requirements { public final class Requirements {
/** /**
* Network types. One of {@link #NETWORK_TYPE_NONE}, {@link #NETWORK_TYPE_ANY}, {@link * Requirement flags. Possible flag values are {@link #NETWORK}, {@link #NETWORK_UNMETERED},
* #NETWORK_TYPE_UNMETERED}, {@link #NETWORK_TYPE_NOT_ROAMING} or {@link #NETWORK_TYPE_METERED}. * {@link #DEVICE_IDLE} and {@link #DEVICE_CHARGING}.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@IntDef({
NETWORK_TYPE_NONE,
NETWORK_TYPE_ANY,
NETWORK_TYPE_UNMETERED,
NETWORK_TYPE_NOT_ROAMING,
NETWORK_TYPE_METERED,
})
public @interface NetworkType {}
/**
* Requirement flags.
*
* <p>Combination of the following values is possible:
*
* <ul>
* <li>Only one of {@link #NETWORK_TYPE_ANY}, {@link #NETWORK_TYPE_UNMETERED}, {@link
* #NETWORK_TYPE_NOT_ROAMING} or {@link #NETWORK_TYPE_METERED}.
* <li>{@link #DEVICE_IDLE}
* <li>{@link #DEVICE_CHARGING}
* <ul>
*/ */
@Documented @Documented
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef( @IntDef(
flag = true, flag = true,
value = { value = {NETWORK, NETWORK_UNMETERED, DEVICE_IDLE, DEVICE_CHARGING})
NETWORK_TYPE_ANY,
NETWORK_TYPE_UNMETERED,
NETWORK_TYPE_NOT_ROAMING,
NETWORK_TYPE_METERED,
DEVICE_IDLE,
DEVICE_CHARGING
})
public @interface RequirementFlags {} public @interface RequirementFlags {}
/** This job doesn't require network connectivity. */ /** Requirement that the device has network connectivity. */
public static final int NETWORK_TYPE_NONE = 0; public static final int NETWORK = 1;
/** This job requires network connectivity. */ /** Requirement that the device has a network connection that is unmetered. */
public static final int NETWORK_TYPE_ANY = 1; public static final int NETWORK_UNMETERED = 1 << 1;
/** This job requires network connectivity that is unmetered. */ /** Requirement that the device is idle. */
public static final int NETWORK_TYPE_UNMETERED = 1 << 1; public static final int DEVICE_IDLE = 1 << 2;
/** This job requires network connectivity that is not roaming. */ /** Requirement that the device is charging. */
public static final int NETWORK_TYPE_NOT_ROAMING = 1 << 2; public static final int DEVICE_CHARGING = 1 << 3;
/** This job requires metered connectivity such as most cellular data networks. */
public static final int NETWORK_TYPE_METERED = 1 << 3;
/** This job requires the device to be idle. */
public static final int DEVICE_IDLE = 1 << 4;
/** This job requires the device to be charging. */
public static final int DEVICE_CHARGING = 1 << 5;
private static final int NETWORK_TYPE_MASK = 0b1111;
private static final String TAG = "Requirements"; private static final String TAG = "Requirements";
private static final String[] NETWORK_TYPE_STRINGS; @RequirementFlags private final int requirements;
static { /** @param requirements A combination of requirement flags. */
if (Scheduler.DEBUG) { public Requirements(@RequirementFlags int requirements) {
NETWORK_TYPE_STRINGS = if ((requirements & NETWORK_UNMETERED) != 0) {
new String[] { // Make sure network requirement flags are consistent.
"NETWORK_TYPE_NONE", requirements |= NETWORK;
"NETWORK_TYPE_ANY",
"NETWORK_TYPE_UNMETERED",
"NETWORK_TYPE_NOT_ROAMING",
"NETWORK_TYPE_METERED"
};
} else {
NETWORK_TYPE_STRINGS = null;
} }
this.requirements = requirements;
} }
@RequirementFlags private final int requirements; /** Returns the requirements. */
@RequirementFlags
/** public int getRequirements() {
* @param networkType Required network type. return requirements;
* @param charging Whether the device should be charging.
* @param idle Whether the device should be idle.
*/
public Requirements(@NetworkType int networkType, boolean charging, boolean idle) {
this(networkType | (charging ? DEVICE_CHARGING : 0) | (idle ? DEVICE_IDLE : 0));
} }
/** @param requirements A combination of requirement flags. */ /** Returns whether network connectivity is required. */
public Requirements(@RequirementFlags int requirements) { public boolean isNetworkRequired() {
this.requirements = requirements; return (requirements & NETWORK) != 0;
int networkType = getRequiredNetworkType();
// Check if only one network type is specified.
Assertions.checkState((networkType & (networkType - 1)) == 0);
} }
/** Returns required network type. */ /** Returns whether un-metered network connectivity is required. */
public int getRequiredNetworkType() { public boolean isUnmeteredNetworkRequired() {
return requirements & NETWORK_TYPE_MASK; return (requirements & NETWORK_UNMETERED) != 0;
} }
/** Returns whether the device should be charging. */ /** Returns whether the device is required to be charging. */
public boolean isChargingRequired() { public boolean isChargingRequired() {
return (requirements & DEVICE_CHARGING) != 0; return (requirements & DEVICE_CHARGING) != 0;
} }
/** Returns whether the device should be idle. */ /** Returns whether the device is required to be idle. */
public boolean isIdleRequired() { public boolean isIdleRequired() {
return (requirements & DEVICE_IDLE) != 0; return (requirements & DEVICE_IDLE) != 0;
} }
...@@ -159,62 +106,47 @@ public final class Requirements { ...@@ -159,62 +106,47 @@ public final class Requirements {
} }
/** /**
* Returns {@link RequirementFlags} that are not met, or 0. * Returns requirements that are not met, or 0.
* *
* @param context Any context. * @param context Any context.
* @return RequirementFlags that are not met, or 0. * @return The requirements that are not met, or 0.
*/ */
@RequirementFlags @RequirementFlags
public int getNotMetRequirements(Context context) { public int getNotMetRequirements(Context context) {
return (!checkNetworkRequirements(context) ? getRequiredNetworkType() : 0) @RequirementFlags int notMetRequirements = getNotMetNetworkRequirements(context);
| (!checkChargingRequirement(context) ? DEVICE_CHARGING : 0) if (isChargingRequired() && !isDeviceCharging(context)) {
| (!checkIdleRequirement(context) ? DEVICE_IDLE : 0); notMetRequirements |= DEVICE_CHARGING;
}
if (isIdleRequired() && !isDeviceIdle(context)) {
notMetRequirements |= DEVICE_IDLE;
}
return notMetRequirements;
} }
/** Returns the requirement flags. */
@RequirementFlags @RequirementFlags
public int getRequirements() { private int getNotMetNetworkRequirements(Context context) {
return requirements; if (!isNetworkRequired()) {
} return 0;
private boolean checkNetworkRequirements(Context context) {
int networkRequirement = getRequiredNetworkType();
if (networkRequirement == NETWORK_TYPE_NONE) {
return true;
} }
ConnectivityManager connectivityManager = ConnectivityManager connectivityManager =
(ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if (networkInfo == null || !networkInfo.isConnected()) { if (networkInfo == null
logd("No network info or no connection."); || !networkInfo.isConnected()
return false; || !isInternetConnectivityValidated(connectivityManager)) {
} logd("No network info, connection or connectivity.");
if (!checkInternetConnectivity(connectivityManager)) { return requirements & (NETWORK | NETWORK_UNMETERED);
return false;
}
if (networkRequirement == NETWORK_TYPE_ANY) {
return true;
} }
if (networkRequirement == NETWORK_TYPE_NOT_ROAMING) {
boolean roaming = networkInfo.isRoaming(); if (isUnmeteredNetworkRequired() && connectivityManager.isActiveNetworkMetered()) {
logd("Roaming: " + roaming); return NETWORK_UNMETERED;
return !roaming;
}
boolean activeNetworkMetered = connectivityManager.isActiveNetworkMetered();
logd("Metered network: " + activeNetworkMetered);
if (networkRequirement == NETWORK_TYPE_UNMETERED) {
return !activeNetworkMetered;
}
if (networkRequirement == NETWORK_TYPE_METERED) {
return activeNetworkMetered;
} }
throw new IllegalStateException();
return 0;
} }
private boolean checkChargingRequirement(Context context) { private boolean isDeviceCharging(Context context) {
if (!isChargingRequired()) {
return true;
}
Intent batteryStatus = Intent batteryStatus =
context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); context.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
if (batteryStatus == null) { if (batteryStatus == null) {
...@@ -225,17 +157,14 @@ public final class Requirements { ...@@ -225,17 +157,14 @@ public final class Requirements {
|| status == BatteryManager.BATTERY_STATUS_FULL; || status == BatteryManager.BATTERY_STATUS_FULL;
} }
private boolean checkIdleRequirement(Context context) { private boolean isDeviceIdle(Context context) {
if (!isIdleRequired()) {
return true;
}
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
return Util.SDK_INT >= 23 return Util.SDK_INT >= 23
? powerManager.isDeviceIdleMode() ? powerManager.isDeviceIdleMode()
: Util.SDK_INT >= 20 ? !powerManager.isInteractive() : !powerManager.isScreenOn(); : Util.SDK_INT >= 20 ? !powerManager.isInteractive() : !powerManager.isScreenOn();
} }
private static boolean checkInternetConnectivity(ConnectivityManager connectivityManager) { private static boolean isInternetConnectivityValidated(ConnectivityManager connectivityManager) {
if (Util.SDK_INT < 23) { if (Util.SDK_INT < 23) {
// TODO Check internet connectivity using http://clients3.google.com/generate_204 on API // TODO Check internet connectivity using http://clients3.google.com/generate_204 on API
// levels prior to 23. // levels prior to 23.
...@@ -262,18 +191,6 @@ public final class Requirements { ...@@ -262,18 +191,6 @@ public final class Requirements {
} }
@Override @Override
public String toString() {
if (!Scheduler.DEBUG) {
return super.toString();
}
return "requirements{"
+ NETWORK_TYPE_STRINGS[getRequiredNetworkType()]
+ (isChargingRequired() ? ",charging" : "")
+ (isIdleRequired() ? ",idle" : "")
+ '}';
}
@Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
return true; return true;
......
...@@ -89,7 +89,7 @@ public final class RequirementsWatcher { ...@@ -89,7 +89,7 @@ public final class RequirementsWatcher {
notMetRequirements = requirements.getNotMetRequirements(context); notMetRequirements = requirements.getNotMetRequirements(context);
IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter();
if (requirements.getRequiredNetworkType() != Requirements.NETWORK_TYPE_NONE) { if (requirements.isNetworkRequired()) {
if (Util.SDK_INT >= 23) { if (Util.SDK_INT >= 23) {
registerNetworkCallbackV23(); registerNetworkCallbackV23();
} else { } else {
......
...@@ -81,7 +81,6 @@ public class DefaultDownloadIndexTest { ...@@ -81,7 +81,6 @@ public class DefaultDownloadIndexTest {
.setDownloadedBytes(200) .setDownloadedBytes(200)
.setTotalBytes(400) .setTotalBytes(400)
.setFailureReason(DownloadState.FAILURE_REASON_UNKNOWN) .setFailureReason(DownloadState.FAILURE_REASON_UNKNOWN)
.setNotMetRequirements(0x87654321)
.setManualStopReason(0x12345678) .setManualStopReason(0x12345678)
.setStartTimeMs(10) .setStartTimeMs(10)
.setUpdateTimeMs(20) .setUpdateTimeMs(20)
......
...@@ -37,7 +37,6 @@ class DownloadStateBuilder { ...@@ -37,7 +37,6 @@ class DownloadStateBuilder {
@Nullable private String cacheKey; @Nullable private String cacheKey;
private int state; private int state;
private int failureReason; private int failureReason;
private int notMetRequirements;
private int manualStopReason; private int manualStopReason;
private long startTimeMs; private long startTimeMs;
private long updateTimeMs; private long updateTimeMs;
...@@ -122,11 +121,6 @@ class DownloadStateBuilder { ...@@ -122,11 +121,6 @@ class DownloadStateBuilder {
return this; return this;
} }
public DownloadStateBuilder setNotMetRequirements(int notMetRequirements) {
this.notMetRequirements = notMetRequirements;
return this;
}
public DownloadStateBuilder setManualStopReason(int manualStopReason) { public DownloadStateBuilder setManualStopReason(int manualStopReason) {
this.manualStopReason = manualStopReason; this.manualStopReason = manualStopReason;
return this; return this;
...@@ -158,7 +152,6 @@ class DownloadStateBuilder { ...@@ -158,7 +152,6 @@ class DownloadStateBuilder {
action, action,
state, state,
failureReason, failureReason,
notMetRequirements,
manualStopReason, manualStopReason,
startTimeMs, startTimeMs,
updateTimeMs, updateTimeMs,
......
...@@ -47,7 +47,7 @@ public class DownloadStateTest { ...@@ -47,7 +47,7 @@ public class DownloadStateTest {
.build(); .build();
try { try {
downloadState.copyWithMergedAction(downloadAction); downloadState.copyWithMergedAction(downloadAction, /* canStart= */ true);
fail(); fail();
} catch (Exception e) { } catch (Exception e) {
// Expected. // Expected.
...@@ -64,7 +64,7 @@ public class DownloadStateTest { ...@@ -64,7 +64,7 @@ public class DownloadStateTest {
.build(); .build();
try { try {
downloadState.copyWithMergedAction(downloadAction); downloadState.copyWithMergedAction(downloadAction, /* canStart= */ true);
fail(); fail();
} catch (Exception e) { } catch (Exception e) {
// Expected. // Expected.
...@@ -78,7 +78,7 @@ public class DownloadStateTest { ...@@ -78,7 +78,7 @@ public class DownloadStateTest {
new DownloadStateBuilder(downloadAction).setState(DownloadState.STATE_QUEUED); new DownloadStateBuilder(downloadAction).setState(DownloadState.STATE_QUEUED);
DownloadState downloadState = downloadStateBuilder.build(); DownloadState downloadState = downloadStateBuilder.build();
downloadState.copyWithMergedAction(downloadAction); downloadState.copyWithMergedAction(downloadAction, /* canStart= */ true);
} }
@Test @Test
...@@ -90,7 +90,8 @@ public class DownloadStateTest { ...@@ -90,7 +90,8 @@ public class DownloadStateTest {
.setState(DownloadState.STATE_QUEUED); .setState(DownloadState.STATE_QUEUED);
DownloadState downloadState = downloadStateBuilder.build(); DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction); DownloadState mergedDownloadState =
downloadState.copyWithMergedAction(downloadAction, /* canStart= */ true);
DownloadState expectedDownloadState = downloadStateBuilder.setUri(downloadAction.uri).build(); DownloadState expectedDownloadState = downloadStateBuilder.setUri(downloadAction.uri).build();
assertEqual(mergedDownloadState, expectedDownloadState); assertEqual(mergedDownloadState, expectedDownloadState);
...@@ -112,7 +113,8 @@ public class DownloadStateTest { ...@@ -112,7 +113,8 @@ public class DownloadStateTest {
.setCustomMetadata(new byte[0]); .setCustomMetadata(new byte[0]);
DownloadState downloadState = downloadStateBuilder.build(); DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction); DownloadState mergedDownloadState =
downloadState.copyWithMergedAction(downloadAction, /* canStart= */ true);
DownloadState expectedDownloadState = DownloadState expectedDownloadState =
downloadStateBuilder.setCustomMetadata(downloadAction.data).build(); downloadStateBuilder.setCustomMetadata(downloadAction.data).build();
...@@ -126,7 +128,8 @@ public class DownloadStateTest { ...@@ -126,7 +128,8 @@ public class DownloadStateTest {
new DownloadStateBuilder(downloadAction).setState(DownloadState.STATE_REMOVING); new DownloadStateBuilder(downloadAction).setState(DownloadState.STATE_REMOVING);
DownloadState downloadState = downloadStateBuilder.build(); DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction); DownloadState mergedDownloadState =
downloadState.copyWithMergedAction(downloadAction, /* canStart= */ true);
DownloadState expectedDownloadState = DownloadState expectedDownloadState =
downloadStateBuilder.setState(DownloadState.STATE_RESTARTING).build(); downloadStateBuilder.setState(DownloadState.STATE_RESTARTING).build();
...@@ -142,7 +145,8 @@ public class DownloadStateTest { ...@@ -142,7 +145,8 @@ public class DownloadStateTest {
.setFailureReason(DownloadState.FAILURE_REASON_UNKNOWN); .setFailureReason(DownloadState.FAILURE_REASON_UNKNOWN);
DownloadState downloadState = downloadStateBuilder.build(); DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction); DownloadState mergedDownloadState =
downloadState.copyWithMergedAction(downloadAction, /* canStart= */ true);
DownloadState expectedDownloadState = DownloadState expectedDownloadState =
downloadStateBuilder downloadStateBuilder
...@@ -161,7 +165,8 @@ public class DownloadStateTest { ...@@ -161,7 +165,8 @@ public class DownloadStateTest {
.setManualStopReason(DownloadState.MANUAL_STOP_REASON_UNDEFINED); .setManualStopReason(DownloadState.MANUAL_STOP_REASON_UNDEFINED);
DownloadState downloadState = downloadStateBuilder.build(); DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction); DownloadState mergedDownloadState =
downloadState.copyWithMergedAction(downloadAction, /* canStart= */ true);
assertEqual(mergedDownloadState, downloadState); assertEqual(mergedDownloadState, downloadState);
} }
...@@ -175,23 +180,8 @@ public class DownloadStateTest { ...@@ -175,23 +180,8 @@ public class DownloadStateTest {
.setManualStopReason(DownloadState.MANUAL_STOP_REASON_UNDEFINED); .setManualStopReason(DownloadState.MANUAL_STOP_REASON_UNDEFINED);
DownloadState downloadState = downloadStateBuilder.build(); DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction); DownloadState mergedDownloadState =
downloadState.copyWithMergedAction(downloadAction, /* canStart= */ true);
DownloadState expectedDownloadState =
downloadStateBuilder.setState(DownloadState.STATE_STOPPED).build();
assertEqual(mergedDownloadState, expectedDownloadState);
}
@Test
public void mergeAction_notMetRequirementsSetButNotInStoppedState_stateBecomesStopped() {
DownloadAction downloadAction = createDownloadAction();
DownloadStateBuilder downloadStateBuilder =
new DownloadStateBuilder(downloadAction)
.setState(DownloadState.STATE_COMPLETED)
.setNotMetRequirements(0x12345678);
DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction);
DownloadState expectedDownloadState = DownloadState expectedDownloadState =
downloadStateBuilder.setState(DownloadState.STATE_STOPPED).build(); downloadStateBuilder.setState(DownloadState.STATE_STOPPED).build();
...@@ -259,7 +249,8 @@ public class DownloadStateTest { ...@@ -259,7 +249,8 @@ public class DownloadStateTest {
.setStreamKeys(keys1); .setStreamKeys(keys1);
DownloadState downloadState = downloadStateBuilder.build(); DownloadState downloadState = downloadStateBuilder.build();
DownloadState mergedDownloadState = downloadState.copyWithMergedAction(downloadAction); DownloadState mergedDownloadState =
downloadState.copyWithMergedAction(downloadAction, /* canStart= */ true);
DownloadState expectedDownloadState = downloadStateBuilder.setStreamKeys(expectedKeys).build(); DownloadState expectedDownloadState = downloadStateBuilder.setStreamKeys(expectedKeys).build();
assertEqual(mergedDownloadState, expectedDownloadState); assertEqual(mergedDownloadState, expectedDownloadState);
...@@ -282,7 +273,6 @@ public class DownloadStateTest { ...@@ -282,7 +273,6 @@ public class DownloadStateTest {
} }
assertThat(downloadState.failureReason).isEqualTo(that.failureReason); assertThat(downloadState.failureReason).isEqualTo(that.failureReason);
assertThat(downloadState.manualStopReason).isEqualTo(that.manualStopReason); assertThat(downloadState.manualStopReason).isEqualTo(that.manualStopReason);
assertThat(downloadState.notMetRequirements).isEqualTo(that.notMetRequirements);
} }
private DownloadAction createDownloadAction() { private DownloadAction createDownloadAction() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment