Merge "Fix bug with cancelled drag" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 15fc149..9834c8c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4359,6 +4359,8 @@
method public android.app.DownloadManager.Request setDestinationUri(android.net.Uri);
method public android.app.DownloadManager.Request setMimeType(java.lang.String);
method public android.app.DownloadManager.Request setNotificationVisibility(int);
+ method public android.app.DownloadManager.Request setRequiresCharging(boolean);
+ method public android.app.DownloadManager.Request setRequiresDeviceIdle(boolean);
method public deprecated android.app.DownloadManager.Request setShowRunningNotification(boolean);
method public android.app.DownloadManager.Request setTitle(java.lang.CharSequence);
method public android.app.DownloadManager.Request setVisibleInDownloadsUi(boolean);
@@ -6335,6 +6337,7 @@
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
+ field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
}
@@ -6382,6 +6385,7 @@
method public abstract void cancel(int);
method public abstract void cancelAll();
method public abstract java.util.List<android.app.job.JobInfo> getAllPendingJobs();
+ method public abstract android.app.job.JobInfo getPendingJob(int);
method public abstract int schedule(android.app.job.JobInfo);
field public static final int RESULT_FAILURE = 0; // 0x0
field public static final int RESULT_SUCCESS = 1; // 0x1
@@ -23757,8 +23761,10 @@
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
+ method public boolean isMetered();
method public boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
public static final class NetworkInfo.DetailedState extends java.lang.Enum {
diff --git a/api/system-current.txt b/api/system-current.txt
index c489435..2755bc8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4502,6 +4502,8 @@
method public android.app.DownloadManager.Request setDestinationUri(android.net.Uri);
method public android.app.DownloadManager.Request setMimeType(java.lang.String);
method public android.app.DownloadManager.Request setNotificationVisibility(int);
+ method public android.app.DownloadManager.Request setRequiresCharging(boolean);
+ method public android.app.DownloadManager.Request setRequiresDeviceIdle(boolean);
method public deprecated android.app.DownloadManager.Request setShowRunningNotification(boolean);
method public android.app.DownloadManager.Request setTitle(java.lang.CharSequence);
method public android.app.DownloadManager.Request setVisibleInDownloadsUi(boolean);
@@ -5085,6 +5087,7 @@
field public static final java.lang.String EXTRA_SHOW_CHRONOMETER = "android.showChronometer";
field public static final java.lang.String EXTRA_SHOW_WHEN = "android.showWhen";
field public static final java.lang.String EXTRA_SMALL_ICON = "android.icon";
+ field public static final java.lang.String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
field public static final java.lang.String EXTRA_SUB_TEXT = "android.subText";
field public static final java.lang.String EXTRA_SUMMARY_TEXT = "android.summaryText";
field public static final java.lang.String EXTRA_TEMPLATE = "android.template";
@@ -6613,6 +6616,7 @@
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
+ field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
}
@@ -6660,6 +6664,7 @@
method public abstract void cancel(int);
method public abstract void cancelAll();
method public abstract java.util.List<android.app.job.JobInfo> getAllPendingJobs();
+ method public abstract android.app.job.JobInfo getPendingJob(int);
method public abstract int schedule(android.app.job.JobInfo);
field public static final int RESULT_FAILURE = 0; // 0x0
field public static final int RESULT_SUCCESS = 1; // 0x1
@@ -25583,8 +25588,10 @@
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
+ method public boolean isMetered();
method public boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
public static final class NetworkInfo.DetailedState extends java.lang.Enum {
diff --git a/api/test-current.txt b/api/test-current.txt
index f6340b2..5dc6d51 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4359,6 +4359,8 @@
method public android.app.DownloadManager.Request setDestinationUri(android.net.Uri);
method public android.app.DownloadManager.Request setMimeType(java.lang.String);
method public android.app.DownloadManager.Request setNotificationVisibility(int);
+ method public android.app.DownloadManager.Request setRequiresCharging(boolean);
+ method public android.app.DownloadManager.Request setRequiresDeviceIdle(boolean);
method public deprecated android.app.DownloadManager.Request setShowRunningNotification(boolean);
method public android.app.DownloadManager.Request setTitle(java.lang.CharSequence);
method public android.app.DownloadManager.Request setVisibleInDownloadsUi(boolean);
@@ -6339,6 +6341,7 @@
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
+ field public static final int NETWORK_TYPE_NOT_ROAMING = 3; // 0x3
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
}
@@ -6386,6 +6389,7 @@
method public abstract void cancel(int);
method public abstract void cancelAll();
method public abstract java.util.List<android.app.job.JobInfo> getAllPendingJobs();
+ method public abstract android.app.job.JobInfo getPendingJob(int);
method public abstract int schedule(android.app.job.JobInfo);
field public static final int RESULT_FAILURE = 0; // 0x0
field public static final int RESULT_SUCCESS = 1; // 0x1
@@ -23825,8 +23829,10 @@
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
+ method public boolean isMetered();
method public boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
public static final class NetworkInfo.DetailedState extends java.lang.Enum {
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index e681d47..29bc4d8 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -370,6 +370,7 @@
* {@link ConnectivityManager#TYPE_BLUETOOTH}.
* @hide
*/
+ @Deprecated
public static final int NETWORK_BLUETOOTH = 1 << 2;
private Uri mUri;
@@ -381,6 +382,7 @@
private int mAllowedNetworkTypes = ~0; // default to all network types allowed
private boolean mRoamingAllowed = true;
private boolean mMeteredAllowed = true;
+ private int mFlags = 0;
private boolean mIsVisibleInDownloadsUi = true;
private boolean mScannable = false;
private boolean mUseSystemCache = false;
@@ -669,6 +671,10 @@
* By default, all network types are allowed. Consider using
* {@link #setAllowedOverMetered(boolean)} instead, since it's more
* flexible.
+ * <p>
+ * As of {@link android.os.Build.VERSION_CODES#N}, setting only the
+ * {@link #NETWORK_WIFI} flag here is equivalent to calling
+ * {@link #setAllowedOverMetered(boolean)} with {@code false}.
*
* @param flags any combination of the NETWORK_* bit flags.
* @return this object
@@ -701,6 +707,42 @@
}
/**
+ * Specify that to run this download, the device needs to be plugged in.
+ * This defaults to false.
+ *
+ * @param requiresCharging Whether or not the device is plugged in.
+ * @see android.app.job.JobInfo.Builder#setRequiresCharging(boolean)
+ */
+ public Request setRequiresCharging(boolean requiresCharging) {
+ if (requiresCharging) {
+ mFlags |= Downloads.Impl.FLAG_REQUIRES_CHARGING;
+ } else {
+ mFlags &= ~Downloads.Impl.FLAG_REQUIRES_CHARGING;
+ }
+ return this;
+ }
+
+ /**
+ * Specify that to run, the download needs the device to be in idle
+ * mode. This defaults to false.
+ * <p>
+ * Idle mode is a loose definition provided by the system, which means
+ * that the device is not in use, and has not been in use for some time.
+ *
+ * @param requiresDeviceIdle Whether or not the device need be within an
+ * idle maintenance window.
+ * @see android.app.job.JobInfo.Builder#setRequiresDeviceIdle(boolean)
+ */
+ public Request setRequiresDeviceIdle(boolean requiresDeviceIdle) {
+ if (requiresDeviceIdle) {
+ mFlags |= Downloads.Impl.FLAG_REQUIRES_DEVICE_IDLE;
+ } else {
+ mFlags &= ~Downloads.Impl.FLAG_REQUIRES_DEVICE_IDLE;
+ }
+ return this;
+ }
+
+ /**
* Set whether this download should be displayed in the system's Downloads UI. True by
* default.
* @param isVisible whether to display this download in the Downloads UI
@@ -746,6 +788,7 @@
values.put(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, mAllowedNetworkTypes);
values.put(Downloads.Impl.COLUMN_ALLOW_ROAMING, mRoamingAllowed);
values.put(Downloads.Impl.COLUMN_ALLOW_METERED, mMeteredAllowed);
+ values.put(Downloads.Impl.COLUMN_FLAGS, mFlags);
values.put(Downloads.Impl.COLUMN_IS_VISIBLE_IN_DOWNLOADS_UI, mIsVisibleInDownloadsUi);
return values;
@@ -983,16 +1026,7 @@
// called with nothing to remove!
throw new IllegalArgumentException("input param 'ids' can't be null");
}
- ContentValues values = new ContentValues();
- values.put(Downloads.Impl.COLUMN_DELETED, 1);
- // if only one id is passed in, then include it in the uri itself.
- // this will eliminate a full database scan in the download service.
- if (ids.length == 1) {
- return mResolver.update(ContentUris.withAppendedId(mBaseUri, ids[0]), values,
- null, null);
- }
- return mResolver.update(mBaseUri, values, getWhereClauseForIds(ids),
- getWhereArgsForIds(ids));
+ return mResolver.delete(mBaseUri, getWhereClauseForIds(ids), getWhereArgsForIds(ids));
}
/**
@@ -1121,6 +1155,20 @@
}
/**
+ * Force the given downloads to proceed even if their size is larger than
+ * {@link #getMaxBytesOverMobile(Context)}.
+ *
+ * @hide
+ */
+ public void forceDownload(long... ids) {
+ ContentValues values = new ContentValues();
+ values.put(Downloads.Impl.COLUMN_STATUS, Downloads.Impl.STATUS_PENDING);
+ values.put(Downloads.Impl.COLUMN_CONTROL, Downloads.Impl.CONTROL_RUN);
+ values.put(Downloads.Impl.COLUMN_BYPASS_RECOMMENDED_SIZE_LIMIT, 1);
+ mResolver.update(mBaseUri, values, getWhereClauseForIds(ids), getWhereArgsForIds(ids));
+ }
+
+ /**
* Returns maximum size, in bytes, of downloads that may go over a mobile connection; or null if
* there's no limit
*
diff --git a/core/java/android/app/JobSchedulerImpl.java b/core/java/android/app/JobSchedulerImpl.java
index b3a486f..e30b96f 100644
--- a/core/java/android/app/JobSchedulerImpl.java
+++ b/core/java/android/app/JobSchedulerImpl.java
@@ -78,4 +78,13 @@
return null;
}
}
+
+ @Override
+ public JobInfo getPendingJob(int jobId) {
+ try {
+ return mBinder.getPendingJob(jobId);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
}
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5becd07..d7705b9 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -976,10 +976,8 @@
*/
public static final String EXTRA_CONTAINS_CUSTOM_VIEW = "android.contains.customView";
- /**
- * @SystemApi
- * @hide
- */
+ /** @hide */
+ @SystemApi
public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
private Icon mSmallIcon;
diff --git a/core/java/android/app/job/IJobScheduler.aidl b/core/java/android/app/job/IJobScheduler.aidl
index 3379f2e..b6eec27 100644
--- a/core/java/android/app/job/IJobScheduler.aidl
+++ b/core/java/android/app/job/IJobScheduler.aidl
@@ -28,4 +28,5 @@
void cancel(int jobId);
void cancelAll();
List<JobInfo> getAllPendingJobs();
+ JobInfo getPendingJob(int jobId);
}
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 602d950..ecfc527 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -44,6 +44,8 @@
public static final int NETWORK_TYPE_ANY = 1;
/** This job requires network connectivity that is unmetered. */
public static final int NETWORK_TYPE_UNMETERED = 2;
+ /** This job requires network connectivity that is not roaming. */
+ public static final int NETWORK_TYPE_NOT_ROAMING = 3;
/**
* Amount of backoff a job has initially by default, in milliseconds.
@@ -240,8 +242,9 @@
/**
* One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY},
- * {@link android.app.job.JobInfo#NETWORK_TYPE_NONE}, or
- * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}.
+ * {@link android.app.job.JobInfo#NETWORK_TYPE_NONE},
+ * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}, or
+ * {@link android.app.job.JobInfo#NETWORK_TYPE_NOT_ROAMING}.
*/
public int getNetworkType() {
return networkType;
diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java
index d1e563f..9618cd10 100644
--- a/core/java/android/app/job/JobScheduler.java
+++ b/core/java/android/app/job/JobScheduler.java
@@ -16,6 +16,9 @@
package android.app.job;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
import java.util.List;
/**
@@ -78,7 +81,6 @@
* Cancel a job that is pending in the JobScheduler.
* @param jobId unique identifier for this job. Obtain this value from the jobs returned by
* {@link #getAllPendingJobs()}.
- * @return
*/
public abstract void cancel(int jobId);
@@ -88,8 +90,18 @@
public abstract void cancelAll();
/**
- * @return a list of all the jobs registered by this package that have not yet been executed.
+ * Retrieve all jobs for this package that are pending in the JobScheduler.
+ *
+ * @return a list of all the jobs registered by this package that have not
+ * yet been executed.
*/
- public abstract List<JobInfo> getAllPendingJobs();
+ public abstract @NonNull List<JobInfo> getAllPendingJobs();
+ /**
+ * Retrieve a specific job for this package that is pending in the
+ * JobScheduler.
+ *
+ * @return job registered by this package that has not yet been executed.
+ */
+ public abstract @Nullable JobInfo getPendingJob(int jobId);
}
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index af7a465..b6c5c6f 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -119,12 +119,9 @@
private String mReason;
private String mExtraInfo;
private boolean mIsFailover;
- private boolean mIsRoaming;
-
- /**
- * Indicates whether network connectivity is possible:
- */
private boolean mIsAvailable;
+ private boolean mIsRoaming;
+ private boolean mIsMetered;
/**
* @hide
@@ -139,8 +136,6 @@
mSubtypeName = subtypeName;
setDetailedState(DetailedState.IDLE, null, null);
mState = State.UNKNOWN;
- mIsAvailable = false; // until we're told otherwise, assume unavailable
- mIsRoaming = false;
}
/** {@hide} */
@@ -156,8 +151,9 @@
mReason = source.mReason;
mExtraInfo = source.mExtraInfo;
mIsFailover = source.mIsFailover;
- mIsRoaming = source.mIsRoaming;
mIsAvailable = source.mIsAvailable;
+ mIsRoaming = source.mIsRoaming;
+ mIsMetered = source.mIsMetered;
}
}
}
@@ -330,6 +326,30 @@
}
/**
+ * Returns if this network is metered. A network is classified as metered
+ * when the user is sensitive to heavy data usage on that connection due to
+ * monetary costs, data limitations or battery/performance issues. You
+ * should check this before doing large data transfers, and warn the user or
+ * delay the operation until another network is available.
+ *
+ * @return {@code true} if large transfers should be avoided, otherwise
+ * {@code false}.
+ */
+ public boolean isMetered() {
+ synchronized (this) {
+ return mIsMetered;
+ }
+ }
+
+ /** {@hide} */
+ @VisibleForTesting
+ public void setMetered(boolean isMetered) {
+ synchronized (this) {
+ mIsMetered = isMetered;
+ }
+ }
+
+ /**
* Reports the current coarse-grained state of the network.
* @return the coarse-grained state
*/
@@ -409,26 +429,21 @@
append("], state: ").append(mState).append("/").append(mDetailedState).
append(", reason: ").append(mReason == null ? "(unspecified)" : mReason).
append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo).
- append(", roaming: ").append(mIsRoaming).
append(", failover: ").append(mIsFailover).
- append(", isAvailable: ").append(mIsAvailable).
+ append(", available: ").append(mIsAvailable).
+ append(", roaming: ").append(mIsRoaming).
+ append(", metered: ").append(mIsMetered).
append("]");
return builder.toString();
}
}
- /**
- * Implement the Parcelable interface
- * @hide
- */
+ @Override
public int describeContents() {
return 0;
}
- /**
- * Implement the Parcelable interface.
- * @hide
- */
+ @Override
public void writeToParcel(Parcel dest, int flags) {
synchronized (this) {
dest.writeInt(mNetworkType);
@@ -440,35 +455,34 @@
dest.writeInt(mIsFailover ? 1 : 0);
dest.writeInt(mIsAvailable ? 1 : 0);
dest.writeInt(mIsRoaming ? 1 : 0);
+ dest.writeInt(mIsMetered ? 1 : 0);
dest.writeString(mReason);
dest.writeString(mExtraInfo);
}
}
- /**
- * Implement the Parcelable interface.
- * @hide
- */
- public static final Creator<NetworkInfo> CREATOR =
- new Creator<NetworkInfo>() {
- public NetworkInfo createFromParcel(Parcel in) {
- int netType = in.readInt();
- int subtype = in.readInt();
- String typeName = in.readString();
- String subtypeName = in.readString();
- NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName);
- netInfo.mState = State.valueOf(in.readString());
- netInfo.mDetailedState = DetailedState.valueOf(in.readString());
- netInfo.mIsFailover = in.readInt() != 0;
- netInfo.mIsAvailable = in.readInt() != 0;
- netInfo.mIsRoaming = in.readInt() != 0;
- netInfo.mReason = in.readString();
- netInfo.mExtraInfo = in.readString();
- return netInfo;
- }
+ public static final Creator<NetworkInfo> CREATOR = new Creator<NetworkInfo>() {
+ @Override
+ public NetworkInfo createFromParcel(Parcel in) {
+ int netType = in.readInt();
+ int subtype = in.readInt();
+ String typeName = in.readString();
+ String subtypeName = in.readString();
+ NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName);
+ netInfo.mState = State.valueOf(in.readString());
+ netInfo.mDetailedState = DetailedState.valueOf(in.readString());
+ netInfo.mIsFailover = in.readInt() != 0;
+ netInfo.mIsAvailable = in.readInt() != 0;
+ netInfo.mIsRoaming = in.readInt() != 0;
+ netInfo.mIsMetered = in.readInt() != 0;
+ netInfo.mReason = in.readString();
+ netInfo.mExtraInfo = in.readString();
+ return netInfo;
+ }
- public NetworkInfo[] newArray(int size) {
- return new NetworkInfo[size];
- }
- };
+ @Override
+ public NetworkInfo[] newArray(int size) {
+ return new NetworkInfo[size];
+ }
+ };
}
diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java
index 933287f..95e3802 100644
--- a/core/java/android/net/NetworkState.java
+++ b/core/java/android/net/NetworkState.java
@@ -25,6 +25,7 @@
* @hide
*/
public class NetworkState implements Parcelable {
+ public static final NetworkState EMPTY = new NetworkState(null, null, null, null, null, null);
public final NetworkInfo networkInfo;
public final LinkProperties linkProperties;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 7f94d0e..b9a3cff 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -3090,7 +3090,7 @@
|| uidWifiRunningTime != 0) {
dumpLine(pw, uid, category, WIFI_DATA, fullWifiLockOnTime, wifiScanTime,
uidWifiRunningTime, wifiScanCount,
- /* legacy fields follow, keep at 0 */ 0, 0, 0, 0);
+ /* legacy fields follow, keep at 0 */ 0, 0, 0);
}
dumpControllerActivityLine(pw, uid, category, WIFI_CONTROLLER_DATA,
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 8472f78..b826584 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -412,6 +412,11 @@
public static final String COLUMN_ALLOW_WRITE = "allow_write";
+ public static final int FLAG_REQUIRES_CHARGING = 1 << 0;
+ public static final int FLAG_REQUIRES_DEVICE_IDLE = 1 << 1;
+
+ public static final String COLUMN_FLAGS = "flags";
+
/**
* default value for {@link #COLUMN_LAST_UPDATESRC}.
* This value is used when this column's value is not relevant.
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 3ec7656..0d51b5b 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -87,7 +87,7 @@
void timeShiftEnablePositionTracking(in IBinder sessionToken, boolean enable, int userId);
// For the recording session
- void startRecording(in IBinder sessionToken, in Uri programHint, int userId);
+ void startRecording(in IBinder sessionToken, in Uri programUri, int userId);
void stopRecording(in IBinder sessionToken, int userId);
// For TV input hardware binding
diff --git a/media/java/android/media/tv/ITvInputSession.aidl b/media/java/android/media/tv/ITvInputSession.aidl
index b1ce8d4..356ec3c 100644
--- a/media/java/android/media/tv/ITvInputSession.aidl
+++ b/media/java/android/media/tv/ITvInputSession.aidl
@@ -56,6 +56,6 @@
void timeShiftEnablePositionTracking(boolean enable);
// For the recording session
- void startRecording(in Uri programHint);
+ void startRecording(in Uri programUri);
void stopRecording();
}
diff --git a/media/java/android/media/tv/ITvInputSessionWrapper.java b/media/java/android/media/tv/ITvInputSessionWrapper.java
index 56103ad..07cfbda 100644
--- a/media/java/android/media/tv/ITvInputSessionWrapper.java
+++ b/media/java/android/media/tv/ITvInputSessionWrapper.java
@@ -352,8 +352,8 @@
}
@Override
- public void startRecording(@Nullable Uri programHint) {
- mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_START_RECORDING, programHint));
+ public void startRecording(@Nullable Uri programUri) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_START_RECORDING, programUri));
}
@Override
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 5c9d2b2..1d894e1 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -2093,16 +2093,16 @@
/**
* Starts TV program recording in the current recording session.
*
- * @param programHint The URI for the TV program to record as a hint, built by
+ * @param programUri The URI for the TV program to record as a hint, built by
* {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
*/
- void startRecording(@Nullable Uri programHint) {
+ void startRecording(@Nullable Uri programUri) {
if (mToken == null) {
Log.w(TAG, "The session has been already released");
return;
}
try {
- mService.startRecording(mToken, programHint, mUserId);
+ mService.startRecording(mToken, programUri, mUserId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 7ae8da0..488b284 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -1695,8 +1695,8 @@
*
* <p>The application may supply the URI for a TV program for filling in program specific
* data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
- * A non-null {@code programHint} implies the started recording should be of that specific
- * program, whereas null {@code programHint} does not impose such a requirement and the
+ * A non-null {@code programUri} implies the started recording should be of that specific
+ * program, whereas null {@code programUri} does not impose such a requirement and the
* recording can span across multiple TV programs. In either case, the application must call
* {@link TvRecordingClient#stopRecording()} to stop the recording.
*
@@ -1761,8 +1761,8 @@
* Calls {@link #onStartRecording(Uri)}.
*
*/
- void startRecording(@Nullable Uri programHint) {
- onStartRecording(programHint);
+ void startRecording(@Nullable Uri programUri) {
+ onStartRecording(programUri);
}
/**
diff --git a/media/java/android/media/tv/TvRecordingClient.java b/media/java/android/media/tv/TvRecordingClient.java
index 2613376..5aadeb6 100644
--- a/media/java/android/media/tv/TvRecordingClient.java
+++ b/media/java/android/media/tv/TvRecordingClient.java
@@ -157,7 +157,7 @@
*
* <p>The application may supply the URI for a TV program for filling in program specific data
* fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
- * A non-null {@code programHint} implies the started recording should be of that specific
+ * A non-null {@code programUri} implies the started recording should be of that specific
* program, whereas null {@code programUri} does not impose such a requirement and the
* recording can span across multiple TV programs. In either case, the application must call
* {@link TvRecordingClient#stopRecording()} to stop the recording.
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 70c8957..31058a9 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -162,6 +162,9 @@
<!-- It's like, reality, but, you know, virtual -->
<uses-permission android:name="android.permission.ACCESS_VR_MANAGER" />
+ <!-- the ability to rename notifications posted by other apps -->
+ <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
+
<application
android:name=".SystemUIApplication"
android:persistent="true"
diff --git a/packages/SystemUI/res/layout/notification_settings_icon_row.xml b/packages/SystemUI/res/layout/notification_settings_icon_row.xml
index f47083a..da3461b90 100644
--- a/packages/SystemUI/res/layout/notification_settings_icon_row.xml
+++ b/packages/SystemUI/res/layout/notification_settings_icon_row.xml
@@ -24,12 +24,9 @@
<com.android.systemui.statusbar.AlphaOptimizedImageView
android:id="@+id/gear_icon"
- android:layout_width="@dimen/notification_gear_width"
- android:layout_height="@dimen/notification_gear_height"
- android:paddingTop="@dimen/notification_gear_top_padding"
- android:paddingStart="@dimen/notification_gear_padding"
- android:paddingEnd="@dimen/notification_gear_padding"
- android:paddingBottom="@dimen/notification_gear_padding"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/notification_gear_padding"
android:src="@drawable/ic_settings"
android:tint="@color/notification_gear_color"
android:alpha="0"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5043610..b8f576b 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -81,13 +81,7 @@
<!-- Width of the space containing the gear icon behind a notification -->
<dimen name="notification_gear_width">64dp</dimen>
- <!-- Height of the space containing the gear icon behind a notification -->
- <dimen name="notification_gear_height">74dp</dimen>
-
- <!-- The space above the gear icon displayed behind a notification -->
- <dimen name="notification_gear_top_padding">30dp</dimen>
-
- <!-- The space on either side and below the gear icon displayed behind a notification -->
+ <!-- The space around the gear icon displayed behind a notification -->
<dimen name="notification_gear_padding">20dp</dimen>
<!-- size at which Notification icons will be drawn in the status bar -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 81fa520..2758551 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -182,7 +182,7 @@
<!-- Notification title displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=50] -->
<string name="screenshot_saved_title">Screenshot captured.</string>
<!-- Notification text displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=100] -->
- <string name="screenshot_saved_text">Touch to view your screenshot.</string>
+ <string name="screenshot_saved_text">Tap to view your screenshot.</string>
<!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
<string name="screenshot_failed_title">Couldn\'t capture screenshot.</string>
<!-- Notification text displayed when we fail to save a screenshot for unknown reasons. [CHAR LIMIT=100] -->
@@ -819,7 +819,7 @@
<string name="speed_bump_explanation">Less urgent notifications below</string>
<!-- Shows to explain the double tap interaction with notifications: After tapping a notification on Keyguard, this will explain users to tap again to launch a notification. [CHAR LIMIT=60] -->
- <string name="notification_tap_again">Touch again to open</string>
+ <string name="notification_tap_again">Tap again to open</string>
<!-- Shows when people have pressed the unlock icon to explain how to unlock. [CHAR LIMIT=60] -->
<string name="keyguard_unlock">Swipe up to unlock</string>
@@ -1054,7 +1054,7 @@
<!-- Screen pinning dialog title. -->
<string name="screen_pinning_title">Screen is pinned</string>
<!-- Screen pinning dialog description. -->
- <string name="screen_pinning_description">This keeps it in view until you unpin. Touch and hold Back to unpin.</string>
+ <string name="screen_pinning_description">This keeps it in view until you unpin. Touch & hold Back to unpin.</string>
<!-- Screen pinning positive response. -->
<string name="screen_pinning_positive">Got it</string>
<!-- Screen pinning negative response. -->
@@ -1082,7 +1082,7 @@
<string name="volumeui_notification_title"><xliff:g id="app_name" example="Volume Prototype 1">%1$s</xliff:g> is the volume dialog</string>
<!-- VolumeUI restoration notification: text -->
- <string name="volumeui_notification_text">Touch to restore the original.</string>
+ <string name="volumeui_notification_text">Tap to restore the original.</string>
<!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
<string name="managed_profile_foreground_toast">You\'re using your work profile</string>
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 9a6fa9c..5c50b5c 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -493,7 +493,15 @@
updateSwipeProgressFromOffset(view, canAnimViewBeDismissed);
}
- public void snapChildIfNeeded(final View view, boolean animate) {
+ /**
+ * Called when a view is updated to be non-dismissable, if the view was being dismissed before
+ * the update this will handle snapping it back into place.
+ *
+ * @param view the view to snap if necessary.
+ * @param animate whether to animate the snap or not.
+ * @param targetLeft the target to snap to.
+ */
+ public void snapChildIfNeeded(final View view, boolean animate, float targetLeft) {
if ((mDragging && mCurrView == view) || mSnappingChild) {
return;
}
@@ -507,7 +515,7 @@
}
if (needToSnap) {
if (animate) {
- snapChild(view, 0 /* targetLeft */, 0.0f /* velocity */);
+ snapChild(view, targetLeft, 0.0f /* velocity */);
} else {
snapChildInstantly(view);
}
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 6f26222..a0aeb2f 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -247,8 +247,8 @@
}
}
} catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Failed to swap drawable; "
- + component.flattenToShortString() + " not found", e);
+ Log.v(TAG, "Assistant component "
+ + component.flattenToShortString() + " not found");
} catch (Resources.NotFoundException nfe) {
Log.w(TAG, "Failed to swap drawable from "
+ component.flattenToShortString(), nfe);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index eb08947..e6cbbea 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -43,6 +43,7 @@
import android.media.MediaActionSound;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Bundle;
import android.os.Environment;
import android.os.Process;
import android.provider.MediaStore;
@@ -164,6 +165,11 @@
c.drawColor(overlayColor);
c.setBitmap(null);
+ // swap "System UI" out for "Android System"
+ final Bundle extras = new Bundle();
+ extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME,
+ context.getString(com.android.internal.R.string.android_system_label));
+
// Show the intermediate notification
mTickerAddSpace = !mTickerAddSpace;
mNotificationManager = nManager;
@@ -180,6 +186,8 @@
.setSmallIcon(R.drawable.stat_notify_image)
.setCategory(Notification.CATEGORY_PROGRESS)
.setWhen(now)
+ .setShowWhen(true)
+ .addExtras(extras)
.setColor(r.getColor(
com.android.internal.R.color.system_notification_accent_color));
@@ -190,6 +198,8 @@
.setContentText(r.getString(R.string.screenshot_saving_text))
.setSmallIcon(R.drawable.stat_notify_image)
.setWhen(now)
+ .setShowWhen(true)
+ .addExtras(extras)
.setColor(r.getColor(com.android.internal.R.color.system_notification_accent_color))
.setStyle(mNotificationStyle)
.setPublicVersion(mPublicNotificationBuilder.build());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 2806729..caa1585 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -263,6 +263,9 @@
int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
: mMaxHeadsUpHeight;
layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
+ if (mSettingsIconRow != null) {
+ mSettingsIconRow.updateVerticalLocation();
+ }
}
public StatusBarNotification getStatusBarNotification() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
index 9ed5022..060d8f4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
@@ -55,8 +55,11 @@
private boolean mOnLeft = true;
private boolean mDismissing = false;
private boolean mSnapping = false;
+ private boolean mIconPlaced = false;
+
private int[] mGearLocation = new int[2];
private int[] mParentLocation = new int[2];
+ private int mVertSpaceForGear;
public NotificationSettingsIconRow(Context context) {
this(context, null);
@@ -83,16 +86,18 @@
setOnClickListener(this);
mHorizSpaceForGear =
getResources().getDimensionPixelOffset(R.dimen.notification_gear_width);
+ mVertSpaceForGear = getResources().getDimensionPixelOffset(R.dimen.notification_min_height);
resetState();
}
public void resetState() {
setGearAlpha(0f);
+ mIconPlaced = false;
mSettingsFadedIn = false;
mAnimating = false;
mSnapping = false;
mDismissing = false;
- setIconLocation(true /* on left */, true /* force */);
+ setIconLocation(true /* on left */);
if (mListener != null) {
mListener.onSettingsIconRowReset(mParent);
}
@@ -104,7 +109,7 @@
public void setNotificationRowParent(ExpandableNotificationRow parent) {
mParent = parent;
- setIconLocation(mOnLeft, true /* force */);
+ setIconLocation(mOnLeft);
}
public void setAppName(String appName) {
@@ -184,7 +189,7 @@
if (isIconLocationChange(transX)) {
setGearAlpha(0f);
}
- setIconLocation(transX > 0 /* fromLeft */, false /* force */);
+ setIconLocation(transX > 0 /* fromLeft */);
mFadeAnimator = ValueAnimator.ofFloat(mGearIcon.getAlpha(), 1);
mFadeAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
@@ -221,22 +226,39 @@
mFadeAnimator.start();
}
- @Override
- public void onRtlPropertiesChanged(int layoutDirection) {
- setIconLocation(mOnLeft, true /* force */);
+ public void updateVerticalLocation() {
+ if (mParent == null) {
+ return;
+ }
+ int parentHeight = mParent.getCollapsedHeight();
+ if (parentHeight < mVertSpaceForGear) {
+ mGearIcon.setTranslationY((parentHeight / 2) - (mGearIcon.getHeight() / 2));
+ } else {
+ mGearIcon.setTranslationY((mVertSpaceForGear - mGearIcon.getHeight()) / 2);
+ }
}
- public void setIconLocation(boolean onLeft, boolean force) {
- if ((!force && onLeft == mOnLeft) || mSnapping || mParent == null) {
+ @Override
+ public void onRtlPropertiesChanged(int layoutDirection) {
+ setIconLocation(mOnLeft);
+ }
+
+ public void setIconLocation(boolean onLeft) {
+ updateVerticalLocation();
+ if ((mIconPlaced && onLeft == mOnLeft) || mSnapping || mParent == null
+ || mGearIcon.getWidth() == 0) {
// Do nothing
return;
}
final boolean isRtl = mParent.isLayoutRtl();
+
// TODO No need to cast to float here once b/28050538 is fixed.
final float left = (float) (isRtl ? -(mParent.getWidth() - mHorizSpaceForGear) : 0);
final float right = (float) (isRtl ? 0 : (mParent.getWidth() - mHorizSpaceForGear));
- setTranslationX(onLeft ? left : right);
+ final float centerX = ((mHorizSpaceForGear - mGearIcon.getWidth()) / 2);
+ setTranslationX(onLeft ? left + centerX : right + centerX);
mOnLeft = onLeft;
+ mIconPlaced = true;
}
public boolean isIconLocationChange(float translation) {
@@ -264,9 +286,8 @@
mParent.getLocationOnScreen(mParentLocation);
final int centerX = (int) (mHorizSpaceForGear / 2);
- // Top / bottom padding are not equal, need to subtract them to get center of gear.
- final int centerY = (int) (mGearIcon.getHeight() - mGearIcon.getPaddingTop()
- - mGearIcon.getPaddingBottom()) / 2 + mGearIcon.getPaddingTop();
+ final int centerY =
+ (int) (mGearIcon.getTranslationY() * 2 + mGearIcon.getHeight())/ 2;
final int x = mGearLocation[0] - mParentLocation[0] + centerX;
final int y = mGearLocation[1] - mParentLocation[1] + centerY;
mListener.onGearTouched(mParent, x, y);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
index 2294931..d90a21d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridView.java
@@ -109,7 +109,7 @@
private void showOfflineAuthUi() {
// TODO: Show keyguard UI in-place.
- mStatusBar.executeRunnableDismissingKeyguard(null, null, true, true);
+ mStatusBar.executeRunnableDismissingKeyguard(null, null, true, true, true);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 83a15ad..8d74536 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -490,7 +490,7 @@
AsyncTask.execute(runnable);
} else {
mPhoneStatusBar.executeRunnableDismissingKeyguard(runnable, null /* cancelAction */,
- false /* dismissShade */, false /* afterKeyguardGone */);
+ false /* dismissShade */, false /* afterKeyguardGone */, true /* deferred */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 8617104..7e2fa2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -1199,7 +1199,7 @@
}
if (mQsFullyExpanded && mFalsingManager.shouldEnforceBouncer()) {
mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
- false /* dismissShade */, true /* afterKeyguardGone */);
+ false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
}
if (DEBUG) {
invalidate();
@@ -1794,7 +1794,8 @@
public void run() {
mKeyguardBottomArea.launchLeftAffordance();
}
- }, null, true /* dismissShade */, false /* afterKeyguardGone */);
+ }, null, true /* dismissShade */, false /* afterKeyguardGone */,
+ true /* deferred */);
}
else {
mKeyguardBottomArea.launchLeftAffordance();
@@ -1813,7 +1814,8 @@
public void run() {
mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
}
- }, null, true /* dismissShade */, false /* afterKeyguardGone */);
+ }, null, true /* dismissShade */, false /* afterKeyguardGone */,
+ true /* deferred */);
}
else {
mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index c36c482..436dc9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3177,13 +3177,14 @@
}
};
executeRunnableDismissingKeyguard(runnable, cancelRunnable, dismissShade,
- afterKeyguardGone);
+ afterKeyguardGone, true /* deferred */);
}
public void executeRunnableDismissingKeyguard(final Runnable runnable,
final Runnable cancelAction,
final boolean dismissShade,
- final boolean afterKeyguardGone) {
+ final boolean afterKeyguardGone,
+ final boolean deferred) {
final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
dismissKeyguardThenExecute(new OnDismissAction() {
@Override
@@ -3206,7 +3207,7 @@
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */,
true /* delayed*/);
}
- return true;
+ return deferred;
}
}, cancelAction, afterKeyguardGone);
}
@@ -3525,7 +3526,7 @@
@Override
public void run() {
mLeaveOpenOnKeyguardHide = true;
- executeRunnableDismissingKeyguard(runnable, null, false, false);
+ executeRunnableDismissingKeyguard(runnable, null, false, false, false);
}
});
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index c962606..3e0f930 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -701,7 +701,7 @@
mFalsingManager.onNotificationDismissed();
if (mFalsingManager.shouldEnforceBouncer()) {
mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
- false /* dismissShade */, true /* afterKeyguardGone */);
+ false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
}
}
@@ -990,9 +990,11 @@
true /* isDismissAll */);
}
- public void snapViewIfNeeded(View child) {
+ public void snapViewIfNeeded(ExpandableNotificationRow child) {
boolean animate = mIsExpanded || isPinnedHeadsUp(child);
- mSwipeHelper.snapChildIfNeeded(child, animate);
+ // If the child is showing the gear to go to settings, snap to that
+ float targetLeft = child.getSettingsRow().isVisible() ? child.getTranslation() : 0;
+ mSwipeHelper.snapChildIfNeeded(child, animate, targetLeft);
}
@Override
@@ -3524,8 +3526,7 @@
} else {
// Check scheduled, reset alpha and update location; check will fade it in
mCurrIconRow.setGearAlpha(0f);
- mCurrIconRow.setIconLocation(translation > 0 /* onLeft */,
- false /* force */);
+ mCurrIconRow.setIconLocation(translation > 0 /* onLeft */);
}
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index b069361..f06583b 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -821,37 +821,25 @@
}
private NetworkState getFilteredNetworkState(int networkType, int uid) {
- NetworkInfo info = null;
- LinkProperties lp = null;
- NetworkCapabilities nc = null;
- Network network = null;
- String subscriberId = null;
-
if (mLegacyTypeTracker.isTypeSupported(networkType)) {
- NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
+ final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
+ final NetworkState state;
if (nai != null) {
- synchronized (nai) {
- info = new NetworkInfo(nai.networkInfo);
- lp = new LinkProperties(nai.linkProperties);
- nc = new NetworkCapabilities(nai.networkCapabilities);
- // Network objects are outwardly immutable so there is no point to duplicating.
- // Duplicating also precludes sharing socket factories and connection pools.
- network = nai.network;
- subscriberId = (nai.networkMisc != null) ? nai.networkMisc.subscriberId : null;
- }
- info.setType(networkType);
+ state = nai.getNetworkState();
+ state.networkInfo.setType(networkType);
} else {
- info = new NetworkInfo(networkType, 0, getNetworkTypeName(networkType), "");
+ final NetworkInfo info = new NetworkInfo(networkType, 0,
+ getNetworkTypeName(networkType), "");
info.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
info.setIsAvailable(true);
- lp = new LinkProperties();
- nc = new NetworkCapabilities();
- network = null;
+ state = new NetworkState(info, new LinkProperties(), new NetworkCapabilities(),
+ null, null, null);
}
- info = getFilteredNetworkInfo(info, lp, uid);
+ filterNetworkStateForUid(state, uid);
+ return state;
+ } else {
+ return NetworkState.EMPTY;
}
-
- return new NetworkState(info, lp, nc, network, subscriberId, null);
}
private NetworkAgentInfo getNetworkAgentInfoForNetwork(Network network) {
@@ -861,7 +849,7 @@
synchronized (mNetworkForNetId) {
return mNetworkForNetId.get(network.netId);
}
- };
+ }
private Network[] getVpnUnderlyingNetworks(int uid) {
if (!mLockdownEnabled) {
@@ -877,12 +865,6 @@
}
private NetworkState getUnfilteredActiveNetworkState(int uid) {
- NetworkInfo info = null;
- LinkProperties lp = null;
- NetworkCapabilities nc = null;
- Network network = null;
- String subscriberId = null;
-
NetworkAgentInfo nai = getDefaultNetwork();
final Network[] networks = getVpnUnderlyingNetworks(uid);
@@ -900,18 +882,10 @@
}
if (nai != null) {
- synchronized (nai) {
- info = new NetworkInfo(nai.networkInfo);
- lp = new LinkProperties(nai.linkProperties);
- nc = new NetworkCapabilities(nai.networkCapabilities);
- // Network objects are outwardly immutable so there is no point to duplicating.
- // Duplicating also precludes sharing socket factories and connection pools.
- network = nai.network;
- subscriberId = (nai.networkMisc != null) ? nai.networkMisc.subscriberId : null;
- }
+ return nai.getNetworkState();
+ } else {
+ return NetworkState.EMPTY;
}
-
- return new NetworkState(info, lp, nc, network, subscriberId, null);
}
/**
@@ -952,21 +926,29 @@
}
/**
- * Return a filtered {@link NetworkInfo}, potentially marked
- * {@link DetailedState#BLOCKED} based on
- * {@link #isNetworkWithLinkPropertiesBlocked}.
+ * Apply any relevant filters to {@link NetworkState} for the given UID. For
+ * example, this may mark the network as {@link DetailedState#BLOCKED} based
+ * on {@link #isNetworkWithLinkPropertiesBlocked}, or
+ * {@link NetworkInfo#isMetered()} based on network policies.
*/
- private NetworkInfo getFilteredNetworkInfo(NetworkInfo info, LinkProperties lp, int uid) {
- if (info != null && isNetworkWithLinkPropertiesBlocked(lp, uid)) {
- // network is blocked; clone and override state
- info = new NetworkInfo(info);
- info.setDetailedState(DetailedState.BLOCKED, null, null);
+ private void filterNetworkStateForUid(NetworkState state, int uid) {
+ if (state == null || state.networkInfo == null || state.linkProperties == null) return;
+
+ if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid)) {
+ state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
}
- if (info != null && mLockdownTracker != null) {
- info = mLockdownTracker.augmentNetworkInfo(info);
- if (VDBG) log("returning Locked NetworkInfo");
+ if (mLockdownTracker != null) {
+ mLockdownTracker.augmentNetworkInfo(state.networkInfo);
}
- return info;
+
+ // TODO: apply metered state closer to NetworkAgentInfo
+ final long token = Binder.clearCallingIdentity();
+ try {
+ state.networkInfo.setMetered(mPolicyManager.isNetworkMetered(state));
+ } catch (RemoteException e) {
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
}
/**
@@ -980,10 +962,10 @@
public NetworkInfo getActiveNetworkInfo() {
enforceAccessPermission();
final int uid = Binder.getCallingUid();
- NetworkState state = getUnfilteredActiveNetworkState(uid);
- NetworkInfo ni = getFilteredNetworkInfo(state.networkInfo, state.linkProperties, uid);
- maybeLogBlockedNetworkInfo(ni, uid);
- return ni;
+ final NetworkState state = getUnfilteredActiveNetworkState(uid);
+ filterNetworkStateForUid(state, uid);
+ maybeLogBlockedNetworkInfo(state.networkInfo, uid);
+ return state.networkInfo;
}
@Override
@@ -1027,8 +1009,9 @@
@Override
public NetworkInfo getActiveNetworkInfoForUid(int uid) {
enforceConnectivityInternalPermission();
- NetworkState state = getUnfilteredActiveNetworkState(uid);
- return getFilteredNetworkInfo(state.networkInfo, state.linkProperties, uid);
+ final NetworkState state = getUnfilteredActiveNetworkState(uid);
+ filterNetworkStateForUid(state, uid);
+ return state.networkInfo;
}
@Override
@@ -1039,12 +1022,13 @@
// A VPN is active, so we may need to return one of its underlying networks. This
// information is not available in LegacyTypeTracker, so we have to get it from
// getUnfilteredActiveNetworkState.
- NetworkState state = getUnfilteredActiveNetworkState(uid);
+ final NetworkState state = getUnfilteredActiveNetworkState(uid);
if (state.networkInfo != null && state.networkInfo.getType() == networkType) {
- return getFilteredNetworkInfo(state.networkInfo, state.linkProperties, uid);
+ filterNetworkStateForUid(state, uid);
+ return state.networkInfo;
}
}
- NetworkState state = getFilteredNetworkState(networkType, uid);
+ final NetworkState state = getFilteredNetworkState(networkType, uid);
return state.networkInfo;
}
@@ -1052,15 +1036,14 @@
public NetworkInfo getNetworkInfoForNetwork(Network network) {
enforceAccessPermission();
final int uid = Binder.getCallingUid();
- NetworkInfo info = null;
- NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
if (nai != null) {
- synchronized (nai) {
- info = new NetworkInfo(nai.networkInfo);
- info = getFilteredNetworkInfo(info, nai.linkProperties, uid);
- }
+ final NetworkState state = nai.getNetworkState();
+ filterNetworkStateForUid(state, uid);
+ return state.networkInfo;
+ } else {
+ return null;
}
- return info;
}
@Override
@@ -1222,12 +1205,7 @@
for (Network network : getAllNetworks()) {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
if (nai != null) {
- synchronized (nai) {
- final String subscriberId = (nai.networkMisc != null)
- ? nai.networkMisc.subscriberId : null;
- result.add(new NetworkState(nai.networkInfo, nai.linkProperties,
- nai.networkCapabilities, network, subscriberId, null));
- }
+ result.add(nai.getNetworkState());
}
}
return result.toArray(new NetworkState[result.size()]);
@@ -1255,24 +1233,9 @@
@Override
public boolean isActiveNetworkMetered() {
enforceAccessPermission();
- final int uid = Binder.getCallingUid();
- final long token = Binder.clearCallingIdentity();
- try {
- return isActiveNetworkMeteredUnchecked(uid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- private boolean isActiveNetworkMeteredUnchecked(int uid) {
- final NetworkState state = getUnfilteredActiveNetworkState(uid);
- if (state.networkInfo != null) {
- try {
- return mPolicyManager.isNetworkMetered(state);
- } catch (RemoteException e) {
- }
- }
- return false;
+ final NetworkInfo info = getActiveNetworkInfo();
+ return (info != null) ? info.isMetered() : false;
}
private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
@@ -1490,7 +1453,8 @@
private Intent makeGeneralIntent(NetworkInfo info, String bcastType) {
if (mLockdownTracker != null) {
- info = mLockdownTracker.augmentNetworkInfo(info);
+ info = new NetworkInfo(info);
+ mLockdownTracker.augmentNetworkInfo(info);
}
Intent intent = new Intent(bcastType);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 1e74f81..9d7ddc7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -11983,8 +11983,12 @@
}
if (receiver != null) {
// Caller wants result sent back to them.
+ Bundle sendBundle = new Bundle();
+ // At least return the receiver extras
+ sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS,
+ pae.receiverExtras);
try {
- pae.receiver.send(0, null);
+ pae.receiver.send(0, sendBundle);
} catch (RemoteException e) {
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index c5d38cb..3201060 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -25,6 +25,7 @@
import android.net.NetworkInfo;
import android.net.NetworkMisc;
import android.net.NetworkRequest;
+import android.net.NetworkState;
import android.os.Handler;
import android.os.Messenger;
import android.util.SparseArray;
@@ -247,6 +248,17 @@
currentScore = newScore;
}
+ public NetworkState getNetworkState() {
+ synchronized (this) {
+ // Network objects are outwardly immutable so there is no point to duplicating.
+ // Duplicating also precludes sharing socket factories and connection pools.
+ final String subscriberId = (networkMisc != null) ? networkMisc.subscriberId : null;
+ return new NetworkState(new NetworkInfo(networkInfo),
+ new LinkProperties(linkProperties),
+ new NetworkCapabilities(networkCapabilities), network, subscriberId, null);
+ }
+ }
+
public String toString() {
return "NetworkAgentInfo{ ni{" + networkInfo + "} " +
"network{" + network + "} nethandle{" + network.getNetworkHandle() + "} " +
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 7df8ffd..075a88f 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -40,6 +40,7 @@
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.Handler;
@@ -336,6 +337,19 @@
}
}
+ public JobInfo getPendingJob(int uid, int jobId) {
+ synchronized (mLock) {
+ List<JobStatus> jobs = mJobs.getJobsByUid(uid);
+ for (int i = jobs.size() - 1; i >= 0; i--) {
+ JobStatus job = jobs.get(i);
+ if (job.getJobId() == jobId) {
+ return job.getJob();
+ }
+ }
+ return null;
+ }
+ }
+
void cancelJobsForUser(int userHandle) {
List<JobStatus> jobsForUser;
synchronized (mLock) {
@@ -912,7 +926,8 @@
if (job.hasIdleConstraint()) {
idleCount++;
}
- if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()) {
+ if (job.hasConnectivityConstraint() || job.hasUnmeteredConstraint()
+ || job.hasNotRoamingConstraint()) {
connectivityCount++;
}
if (job.hasChargingConstraint()) {
@@ -1346,6 +1361,18 @@
}
@Override
+ public JobInfo getPendingJob(int jobId) throws RemoteException {
+ final int uid = Binder.getCallingUid();
+
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return JobSchedulerService.this.getPendingJob(uid, jobId);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+
+ @Override
public void cancelAll() throws RemoteException {
final int uid = Binder.getCallingUid();
@@ -1378,7 +1405,7 @@
long identityToken = Binder.clearCallingIdentity();
try {
- JobSchedulerService.this.dumpInternal(pw);
+ JobSchedulerService.this.dumpInternal(pw, args);
} finally {
Binder.restoreCallingIdentity(identityToken);
}
@@ -1450,7 +1477,17 @@
return s.toString();
}
- void dumpInternal(final PrintWriter pw) {
+ void dumpInternal(final PrintWriter pw, String[] args) {
+ int filterUid = -1;
+ if (!ArrayUtils.isEmpty(args)) {
+ try {
+ filterUid = getContext().getPackageManager().getPackageUid(args[0],
+ PackageManager.MATCH_UNINSTALLED_PACKAGES);
+ } catch (NameNotFoundException ignored) {
+ }
+ }
+
+ final int filterUidFinal = filterUid;
final long now = SystemClock.elapsedRealtime();
synchronized (mLock) {
pw.println("Started users: " + Arrays.toString(mStartedUsers));
@@ -1463,6 +1500,13 @@
public void process(JobStatus job) {
pw.print(" Job #"); pw.print(index++); pw.print(": ");
pw.println(job.toShortString());
+
+ // Skip printing details if the caller requested a filter
+ if (filterUidFinal != -1 && job.getUid() != filterUidFinal
+ && job.getSourceUid() != filterUidFinal) {
+ return;
+ }
+
job.dump(pw, " ", true);
pw.print(" Ready: ");
pw.print(mHandler.isReadyToBeExecutedLocked(job));
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 35628a2..5ad988a 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -365,11 +365,14 @@
*/
private void writeConstraintsToXml(XmlSerializer out, JobStatus jobStatus) throws IOException {
out.startTag(null, XML_TAG_PARAMS_CONSTRAINTS);
+ if (jobStatus.hasConnectivityConstraint()) {
+ out.attribute(null, "connectivity", Boolean.toString(true));
+ }
if (jobStatus.hasUnmeteredConstraint()) {
out.attribute(null, "unmetered", Boolean.toString(true));
}
- if (jobStatus.hasConnectivityConstraint()) {
- out.attribute(null, "connectivity", Boolean.toString(true));
+ if (jobStatus.hasNotRoamingConstraint()) {
+ out.attribute(null, "not-roaming", Boolean.toString(true));
}
if (jobStatus.hasIdleConstraint()) {
out.attribute(null, "idle", Boolean.toString(true));
@@ -693,13 +696,17 @@
}
private void buildConstraintsFromXml(JobInfo.Builder jobBuilder, XmlPullParser parser) {
- String val = parser.getAttributeValue(null, "unmetered");
+ String val = parser.getAttributeValue(null, "connectivity");
+ if (val != null) {
+ jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ }
+ val = parser.getAttributeValue(null, "unmetered");
if (val != null) {
jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);
}
- val = parser.getAttributeValue(null, "connectivity");
+ val = parser.getAttributeValue(null, "not-roaming");
if (val != null) {
- jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
+ jobBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_NOT_ROAMING);
}
val = parser.getAttributeValue(null, "idle");
if (val != null) {
diff --git a/services/core/java/com/android/server/job/controllers/ConnectivityController.java b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
index be9d800..88cf322 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -16,44 +16,44 @@
package com.android.server.job.controllers;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
+import android.net.INetworkPolicyListener;
import android.net.NetworkInfo;
-import android.os.ServiceManager;
+import android.net.NetworkPolicyManager;
import android.os.UserHandle;
import android.util.Slog;
-import com.android.server.ConnectivityService;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.job.JobSchedulerService;
import com.android.server.job.StateChangedListener;
import java.io.PrintWriter;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.ArrayList;
/**
* Handles changes in connectivity.
- * We are only interested in metered vs. unmetered networks, and we're interested in them on a
- * per-user basis.
+ * <p>
+ * Each app can have a different default networks or different connectivity
+ * status due to user-requested network policies, so we need to check
+ * constraints on a per-UID basis.
*/
public class ConnectivityController extends StateController implements
ConnectivityManager.OnNetworkActiveListener {
private static final String TAG = "JobScheduler.Conn";
- private final List<JobStatus> mTrackedJobs = new LinkedList<JobStatus>();
- private final BroadcastReceiver mConnectivityChangedReceiver =
- new ConnectivityChangedReceiver();
+ private final ConnectivityManager mConnManager;
+ private final NetworkPolicyManager mNetPolicyManager;
+
+ @GuardedBy("mLock")
+ private final ArrayList<JobStatus> mTrackedJobs = new ArrayList<JobStatus>();
+
/** Singleton. */
private static ConnectivityController mSingleton;
private static Object sCreationLock = new Object();
- /** Track whether the latest active network is metered. */
- private boolean mNetworkUnmetered;
- /** Track whether the latest active network is connected. */
- private boolean mNetworkConnected;
public static ConnectivityController get(JobSchedulerService jms) {
synchronized (sCreationLock) {
@@ -67,51 +67,62 @@
private ConnectivityController(StateChangedListener stateChangedListener, Context context,
Object lock) {
super(stateChangedListener, context, lock);
- // Register connectivity changed BR.
- IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+
+ mConnManager = mContext.getSystemService(ConnectivityManager.class);
+ mNetPolicyManager = mContext.getSystemService(NetworkPolicyManager.class);
+
+ final IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiverAsUser(
- mConnectivityChangedReceiver, UserHandle.ALL, intentFilter, null, null);
- ConnectivityService cs =
- (ConnectivityService)ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
- if (cs != null) {
- if (cs.getActiveNetworkInfo() != null) {
- mNetworkConnected = cs.getActiveNetworkInfo().isConnected();
- mNetworkUnmetered = mNetworkConnected && !cs.isActiveNetworkMetered();
- } else {
- mNetworkConnected = mNetworkUnmetered = false;
- }
- }
+ mConnectivityReceiver, UserHandle.SYSTEM, intentFilter, null, null);
+
+ mNetPolicyManager.registerListener(mNetPolicyListener);
}
@Override
public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
- if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
- jobStatus.setConnectivityConstraintSatisfied(mNetworkConnected);
- jobStatus.setUnmeteredConstraintSatisfied(mNetworkUnmetered);
+ if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()
+ || jobStatus.hasNotRoamingConstraint()) {
+ updateConstraintsSatisfied(jobStatus);
mTrackedJobs.add(jobStatus);
}
}
@Override
- public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) {
- if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()) {
+ public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob,
+ boolean forUpdate) {
+ if (jobStatus.hasConnectivityConstraint() || jobStatus.hasUnmeteredConstraint()
+ || jobStatus.hasNotRoamingConstraint()) {
mTrackedJobs.remove(jobStatus);
}
}
+ private boolean updateConstraintsSatisfied(JobStatus jobStatus) {
+ final NetworkInfo info = mConnManager.getActiveNetworkInfoForUid(jobStatus.getSourceUid());
+ final boolean connected = (info != null) && info.isConnected();
+ final boolean unmetered = connected && !info.isMetered();
+ final boolean notRoaming = connected && !info.isRoaming();
+
+ boolean changed = false;
+ changed |= jobStatus.setConnectivityConstraintSatisfied(connected);
+ changed |= jobStatus.setUnmeteredConstraintSatisfied(unmetered);
+ changed |= jobStatus.setNotRoamingConstraintSatisfied(notRoaming);
+ return changed;
+ }
+
/**
- * @param userId Id of the user for whom we are updating the connectivity state.
+ * Update all jobs tracked by this controller.
+ *
+ * @param uid only update jobs belonging to this UID, or {@code -1} to
+ * update all tracked jobs.
*/
- private void updateTrackedJobs(int userId) {
+ private void updateTrackedJobs(int uid) {
synchronized (mLock) {
boolean changed = false;
- for (JobStatus js : mTrackedJobs) {
- if (js.getUserId() != userId) {
- continue;
+ for (int i = 0; i < mTrackedJobs.size(); i++) {
+ final JobStatus js = mTrackedJobs.get(i);
+ if (uid == -1 || uid == js.getSourceUid()) {
+ changed |= updateConstraintsSatisfied(js);
}
- changed |= js.setConnectivityConstraintSatisfied(mNetworkConnected);
- changed |= js.setUnmeteredConstraintSatisfied(mNetworkUnmetered);
}
if (changed) {
mStateChangedListener.onControllerStateChanged();
@@ -122,9 +133,11 @@
/**
* We know the network has just come up. We want to run any jobs that are ready.
*/
+ @Override
public synchronized void onNetworkActive() {
synchronized (mLock) {
- for (JobStatus js : mTrackedJobs) {
+ for (int i = 0; i < mTrackedJobs.size(); i++) {
+ final JobStatus js = mTrackedJobs.get(i);
if (js.isReady()) {
if (DEBUG) {
Slog.d(TAG, "Running " + js + " due to network activity.");
@@ -135,61 +148,44 @@
}
}
- class ConnectivityChangedReceiver extends BroadcastReceiver {
- /**
- * We'll receive connectivity changes for each user here, which we process independently.
- * We are only interested in the active network here. We're only interested in the active
- * network, b/c the end result of this will be for apps to try to hit the network.
- * @param context The Context in which the receiver is running.
- * @param intent The Intent being received.
- */
- // TODO: Test whether this will be called twice for each user.
+ private BroadcastReceiver mConnectivityReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (DEBUG) {
- Slog.d(TAG, "Received connectivity event: " + intent.getAction() + " u"
- + context.getUserId());
- }
- final String action = intent.getAction();
- if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
- final int networkType =
- intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE,
- ConnectivityManager.TYPE_NONE);
- // Connectivity manager for THIS context - important!
- final ConnectivityManager connManager = (ConnectivityManager)
- context.getSystemService(Context.CONNECTIVITY_SERVICE);
- final NetworkInfo activeNetwork = connManager.getActiveNetworkInfo();
- final int userid = context.getUserId();
- // This broadcast gets sent a lot, only update if the active network has changed.
- if (activeNetwork == null) {
- mNetworkUnmetered = false;
- mNetworkConnected = false;
- updateTrackedJobs(userid);
- } else if (activeNetwork.getType() == networkType) {
- mNetworkUnmetered = false;
- mNetworkConnected = !intent.getBooleanExtra(
- ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
- if (mNetworkConnected) { // No point making the call if we know there's no conn.
- mNetworkUnmetered = !connManager.isActiveNetworkMetered();
- }
- updateTrackedJobs(userid);
- }
- } else {
- if (DEBUG) {
- Slog.d(TAG, "Unrecognised action in intent: " + action);
- }
- }
+ updateTrackedJobs(-1);
+ }
+ };
+
+ private INetworkPolicyListener mNetPolicyListener = new INetworkPolicyListener.Stub() {
+ @Override
+ public void onUidRulesChanged(int uid, int uidRules) {
+ updateTrackedJobs(uid);
+ }
+
+ @Override
+ public void onMeteredIfacesChanged(String[] meteredIfaces) {
+ updateTrackedJobs(-1);
+ }
+
+ @Override
+ public void onRestrictBackgroundChanged(boolean restrictBackground) {
+ updateTrackedJobs(-1);
+ }
+
+ @Override
+ public void onRestrictBackgroundWhitelistChanged(int uid, boolean whitelisted) {
+ updateTrackedJobs(uid);
}
};
@Override
public void dumpControllerStateLocked(PrintWriter pw) {
pw.println("Conn.");
- pw.println("connected: " + mNetworkConnected + " unmetered: " + mNetworkUnmetered);
- for (JobStatus js: mTrackedJobs) {
+ for (int i = 0; i < mTrackedJobs.size(); i++) {
+ final JobStatus js = mTrackedJobs.get(i);
pw.println(String.valueOf(js.getJobId() + "," + js.getUid())
+ ": C=" + js.hasConnectivityConstraint()
- + ", UM=" + js.hasUnmeteredConstraint());
+ + ", UM=" + js.hasUnmeteredConstraint()
+ + ", NR=" + js.hasNotRoamingConstraint());
}
}
}
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index dd70758..9ab4386 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -29,7 +29,6 @@
import android.util.TimeUtils;
import java.io.PrintWriter;
-import java.util.concurrent.atomic.AtomicBoolean;
/**
* Uniquely identifies a job internally.
@@ -55,6 +54,7 @@
static final int CONSTRAINT_APP_NOT_IDLE = 1<<6;
static final int CONSTRAINT_CONTENT_TRIGGER = 1<<7;
static final int CONSTRAINT_DEVICE_NOT_DOZING = 1<<8;
+ static final int CONSTRAINT_NOT_ROAMING = 1<<9;
// Soft override: ignore constraints like time that don't affect API availability
public static final int OVERRIDE_SOFT = 1;
@@ -176,6 +176,9 @@
if (job.getNetworkType() == JobInfo.NETWORK_TYPE_UNMETERED) {
requiredConstraints |= CONSTRAINT_UNMETERED;
}
+ if (job.getNetworkType() == JobInfo.NETWORK_TYPE_NOT_ROAMING) {
+ requiredConstraints |= CONSTRAINT_NOT_ROAMING;
+ }
if (job.isRequireCharging()) {
requiredConstraints |= CONSTRAINT_CHARGING;
}
@@ -312,6 +315,10 @@
return (requiredConstraints&CONSTRAINT_UNMETERED) != 0;
}
+ public boolean hasNotRoamingConstraint() {
+ return (requiredConstraints&CONSTRAINT_NOT_ROAMING) != 0;
+ }
+
public boolean hasChargingConstraint() {
return (requiredConstraints&CONSTRAINT_CHARGING) != 0;
}
@@ -376,12 +383,16 @@
return setConstraintSatisfied(CONSTRAINT_IDLE, state);
}
+ boolean setConnectivityConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
+ }
+
boolean setUnmeteredConstraintSatisfied(boolean state) {
return setConstraintSatisfied(CONSTRAINT_UNMETERED, state);
}
- boolean setConnectivityConstraintSatisfied(boolean state) {
- return setConstraintSatisfied(CONSTRAINT_CONNECTIVITY, state);
+ boolean setNotRoamingConstraintSatisfied(boolean state) {
+ return setConstraintSatisfied(CONSTRAINT_NOT_ROAMING, state);
}
boolean setAppNotIdleConstraintSatisfied(boolean state) {
@@ -425,7 +436,7 @@
static final int CONSTRAINTS_OF_INTEREST =
CONSTRAINT_CHARGING | CONSTRAINT_TIMING_DELAY |
- CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED |
+ CONSTRAINT_CONNECTIVITY | CONSTRAINT_UNMETERED | CONSTRAINT_NOT_ROAMING |
CONSTRAINT_IDLE | CONSTRAINT_CONTENT_TRIGGER;
// Soft override covers all non-"functional" constraints
@@ -517,11 +528,14 @@
if ((constraints&CONSTRAINT_IDLE) != 0) {
pw.print(" IDLE");
}
+ if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
+ pw.print(" CONNECTIVITY");
+ }
if ((constraints&CONSTRAINT_UNMETERED) != 0) {
pw.print(" UNMETERED");
}
- if ((constraints&CONSTRAINT_CONNECTIVITY) != 0) {
- pw.print(" CONNECTIVITY");
+ if ((constraints&CONSTRAINT_NOT_ROAMING) != 0) {
+ pw.print(" NOT_ROAMING");
}
if ((constraints&CONSTRAINT_APP_NOT_IDLE) != 0) {
pw.print(" APP_NOT_IDLE");
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index fc412e3..4a8539a 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -209,7 +209,9 @@
throw new RuntimeException("Problem setting firewall rules", e);
}
- mConnService.sendConnectedBroadcast(augmentNetworkInfo(egressInfo));
+ final NetworkInfo clone = new NetworkInfo(egressInfo);
+ augmentNetworkInfo(clone);
+ mConnService.sendConnectedBroadcast(clone);
}
}
@@ -320,13 +322,11 @@
}
}
- public NetworkInfo augmentNetworkInfo(NetworkInfo info) {
+ public void augmentNetworkInfo(NetworkInfo info) {
if (info.isConnected()) {
final NetworkInfo vpnInfo = mVpn.getNetworkInfo();
- info = new NetworkInfo(info);
info.setDetailedState(vpnInfo.getDetailedState(), vpnInfo.getReason(), null);
}
- return info;
}
private void showNotification(int titleRes, int iconRes) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 433c056..43f47fa 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2148,6 +2148,10 @@
@Override
public boolean isNetworkMetered(NetworkState state) {
+ if (state.networkInfo == null) {
+ return false;
+ }
+
final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state);
// roaming networks are always considered metered
@@ -2163,10 +2167,6 @@
if (policy != null) {
return policy.metered;
} else {
- if (state.networkInfo == null) {
- return false;
- }
-
final int type = state.networkInfo.getType();
if (isNetworkTypeMobile(type) || type == TYPE_WIMAX) {
return true;
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index e13ee13..b389cf5 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -1557,7 +1557,7 @@
}
@Override
- public void startRecording(IBinder sessionToken, @Nullable Uri programHint, int userId) {
+ public void startRecording(IBinder sessionToken, @Nullable Uri programUri, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "startRecording");
@@ -1566,7 +1566,7 @@
synchronized (mLock) {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId).startRecording(
- programHint);
+ programUri);
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in startRecording", e);
}