Merge "Downgrade OOB warning of priv app to warning" into pi-dev
diff --git a/Android.mk b/Android.mk
index e2f88e8..b630c3f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -869,11 +869,27 @@
 $(eval $(call copy-one-file,frameworks/base/config/hiddenapi-blacklist.txt,\
                             $(INTERNAL_PLATFORM_HIDDENAPI_BLACKLIST)))
 
+# Automatically add all methods which match the following signatures.
+# These need to be greylisted in order to allow applications to write their
+# own serializers.
+$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): REGEX_SERIALIZATION := \
+    "readObject\(Ljava/io/ObjectInputStream;\)V" \
+    "readObjectNoData\(\)V" \
+    "readResolve\(\)Ljava/lang/Object;" \
+    "serialVersionUID:J" \
+    "serialPersistentFields:\[Ljava/io/ObjectStreamField;" \
+    "writeObject\(Ljava/io/ObjectOutputStream;\)V" \
+    "writeReplace\(\)Ljava/lang/Object;"
+$(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): PRIVATE_API := $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
 # Temporarily merge light greylist from two files. Vendor list will become dark
 # grey once we remove the UI toast.
 $(INTERNAL_PLATFORM_HIDDENAPI_LIGHT_GREYLIST): frameworks/base/config/hiddenapi-light-greylist.txt \
-                                               frameworks/base/config/hiddenapi-vendor-list.txt
-	sort $^ > $@
+                                               frameworks/base/config/hiddenapi-vendor-list.txt \
+                                               $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
+	sort frameworks/base/config/hiddenapi-light-greylist.txt \
+	     frameworks/base/config/hiddenapi-vendor-list.txt \
+	     <(grep -E "\->("$(subst $(space),"|",$(REGEX_SERIALIZATION))")$$" $(PRIVATE_API)) \
+	> $@
 
 # Generate dark greylist as private API minus (blacklist plus light greylist).
 
diff --git a/api/current.txt b/api/current.txt
index be5e3e7..64b2d58 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7041,7 +7041,8 @@
     method public int getBackoffPolicy();
     method public android.content.ClipData getClipData();
     method public int getClipGrantFlags();
-    method public long getEstimatedNetworkBytes();
+    method public long getEstimatedNetworkDownloadBytes();
+    method public long getEstimatedNetworkUploadBytes();
     method public android.os.PersistableBundle getExtras();
     method public long getFlexMillis();
     method public int getId();
@@ -7058,8 +7059,10 @@
     method public long getTriggerContentMaxDelay();
     method public long getTriggerContentUpdateDelay();
     method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
+    method public boolean isImportantWhileForeground();
     method public boolean isPeriodic();
     method public boolean isPersisted();
+    method public boolean isPrefetch();
     method public boolean isRequireBatteryNotLow();
     method public boolean isRequireCharging();
     method public boolean isRequireDeviceIdle();
@@ -7085,15 +7088,15 @@
     method public android.app.job.JobInfo build();
     method public android.app.job.JobInfo.Builder setBackoffCriteria(long, int);
     method public android.app.job.JobInfo.Builder setClipData(android.content.ClipData, int);
-    method public android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long);
+    method public android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long, long);
     method public android.app.job.JobInfo.Builder setExtras(android.os.PersistableBundle);
     method public android.app.job.JobInfo.Builder setImportantWhileForeground(boolean);
-    method public android.app.job.JobInfo.Builder setIsPrefetch(boolean);
     method public android.app.job.JobInfo.Builder setMinimumLatency(long);
     method public android.app.job.JobInfo.Builder setOverrideDeadline(long);
     method public android.app.job.JobInfo.Builder setPeriodic(long);
     method public android.app.job.JobInfo.Builder setPeriodic(long, long);
     method public android.app.job.JobInfo.Builder setPersisted(boolean);
+    method public android.app.job.JobInfo.Builder setPrefetch(boolean);
     method public android.app.job.JobInfo.Builder setRequiredNetwork(android.net.NetworkRequest);
     method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
     method public android.app.job.JobInfo.Builder setRequiresBatteryNotLow(boolean);
@@ -7163,10 +7166,11 @@
 
   public final class JobWorkItem implements android.os.Parcelable {
     ctor public JobWorkItem(android.content.Intent);
-    ctor public JobWorkItem(android.content.Intent, long);
+    ctor public JobWorkItem(android.content.Intent, long, long);
     method public int describeContents();
     method public int getDeliveryCount();
-    method public long getEstimatedNetworkBytes();
+    method public long getEstimatedNetworkDownloadBytes();
+    method public long getEstimatedNetworkUploadBytes();
     method public android.content.Intent getIntent();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.job.JobWorkItem> CREATOR;
diff --git a/api/removed.txt b/api/removed.txt
index 64a9c3f..4279c31 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -54,6 +54,24 @@
 
 }
 
+package android.app.job {
+
+  public class JobInfo implements android.os.Parcelable {
+    method public deprecated long getEstimatedNetworkBytes();
+  }
+
+  public static final class JobInfo.Builder {
+    method public deprecated android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long);
+    method public deprecated android.app.job.JobInfo.Builder setIsPrefetch(boolean);
+  }
+
+  public final class JobWorkItem implements android.os.Parcelable {
+    ctor public deprecated JobWorkItem(android.content.Intent, long);
+    method public deprecated long getEstimatedNetworkBytes();
+  }
+
+}
+
 package android.app.usage {
 
   public final class StorageStats implements android.os.Parcelable {
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 0afc1ce..8e2e43c 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -822,56 +822,24 @@
 Landroid/hardware/usb/UsbRequest;->mLength:I
 Landroid/hardware/usb/UsbRequest;->mNativeContext:J
 Landroid/icu/impl/CurrencyData;-><init>()V
-Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/impl/number/DecimalFormatProperties;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/impl/TimeZoneGenericNames;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/ArabicShaping;->isAlefMaksouraChar(C)Z
 Landroid/icu/text/ArabicShaping;->isSeenTailFamilyChar(C)I
 Landroid/icu/text/ArabicShaping;->isTailChar(C)Z
 Landroid/icu/text/ArabicShaping;->isYehHamzaChar(C)Z
-Landroid/icu/text/DateFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/DateFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/DateIntervalFormat;-><init>()V
-Landroid/icu/text/DateIntervalFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/DateTimePatternGenerator$DistanceInfo;-><init>()V
-Landroid/icu/text/DecimalFormat_ICU58_Android;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/DecimalFormat_ICU58_Android;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/icu/text/DecimalFormatSymbols;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/MessageFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/NumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/NumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/PluralFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/PluralRules$FixedDecimal;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/PluralRules$FixedDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/PluralRules;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/PluralRules;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/text/RuleBasedCollator;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/text/RuleBasedNumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/RuleBasedNumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/text/SelectFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/SimpleDateFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/text/SpoofChecker$ScriptSet;->and(I)V
 Landroid/icu/text/SpoofChecker$ScriptSet;-><init>()V
 Landroid/icu/text/SpoofChecker$ScriptSet;->isFull()Z
 Landroid/icu/text/SpoofChecker$ScriptSet;->setAll()V
-Landroid/icu/text/TimeZoneFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/text/TimeZoneFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
 Landroid/icu/text/TimeZoneNames$DefaultTimeZoneNames$FactoryImpl;-><init>()V
 Landroid/icu/text/Transliterator;->createFromRules(Ljava/lang/String;Ljava/lang/String;I)Landroid/icu/text/Transliterator;
 Landroid/icu/text/Transliterator;->transliterate(Ljava/lang/String;)Ljava/lang/String;
 Landroid/icu/text/UFormat;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
 Landroid/icu/util/Calendar;->getLocale(Landroid/icu/util/ULocale$Type;)Landroid/icu/util/ULocale;
-Landroid/icu/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V
-Landroid/icu/util/ChineseCalendar;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/util/IslamicCalendar;->readObject(Ljava/io/ObjectInputStream;)V
-Landroid/icu/util/SimpleTimeZone;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/inputmethodservice/InputMethodService;->mExtractEditText:Landroid/inputmethodservice/ExtractEditText;
 Landroid/location/CountryDetector;->detectCountry()Landroid/location/Country;
 Landroid/location/Country;->getCountryIso()Ljava/lang/String;
@@ -1989,7 +1957,6 @@
 Landroid/util/Pools$SynchronizedPool;-><init>(I)V
 Landroid/util/Rational;->mDenominator:I
 Landroid/util/Rational;->mNumerator:I
-Landroid/util/Rational;->readObject(Ljava/io/ObjectInputStream;)V
 Landroid/util/Singleton;->mInstance:Ljava/lang/Object;
 Landroid/util/Slog;->d(Ljava/lang/String;Ljava/lang/String;)I
 Landroid/util/SparseIntArray;->mKeys:[I
@@ -2838,8 +2805,6 @@
 Lcom/android/okhttp/OkHttpClient;->dns:Lcom/android/okhttp/Dns;
 Lcom/android/okhttp/OkHttpClient;->setProtocols(Ljava/util/List;)Lcom/android/okhttp/OkHttpClient;
 Lcom/android/okhttp/OkHttpClient;->setRetryOnConnectionFailure(Z)V
-Lcom/android/okhttp/okio/ByteString;->readObject(Ljava/io/ObjectInputStream;)V
-Lcom/android/okhttp/okio/ByteString;->writeObject(Ljava/io/ObjectOutputStream;)V
 Lcom/android/okhttp/Request;->headers:Lcom/android/okhttp/Headers;
 Lcom/android/okhttp/Request;->method:Ljava/lang/String;
 Lcom/android/okhttp/Request;->url:Lcom/android/okhttp/HttpUrl;
@@ -2942,20 +2907,14 @@
 Ldalvik/system/VMRuntime;->vmLibrary()Ljava/lang/String;
 Ldalvik/system/VMStack;->getCallingClassLoader()Ljava/lang/ClassLoader;
 Ldalvik/system/VMStack;->getStackClass2()Ljava/lang/Class;
-Ljava/awt/font/NumericShaper;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/beans/PropertyChangeSupport;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/beans/PropertyChangeSupport;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/io/FileDescriptor;->descriptor:I
 Ljava/io/FileDescriptor;->getInt$()I
 Ljava/io/FileDescriptor;->setInt$(I)V
 Ljava/io/FileInputStream;->fd:Ljava/io/FileDescriptor;
 Ljava/io/FileOutputStream;->fd:Ljava/io/FileDescriptor;
-Ljava/io/File;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/io/File;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/io/ObjectStreamClass;->getConstructorId(Ljava/lang/Class;)J
 Ljava/io/ObjectStreamClass;->newInstance(Ljava/lang/Class;J)Ljava/lang/Object;
 Ljava/io/ObjectStreamClass;->newInstance()Ljava/lang/Object;
-Ljava/io/UncheckedIOException;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/lang/AbstractStringBuilder;->value:[C
 Ljava/lang/Boolean;->value:Z
 Ljava/lang/Byte;->value:B
@@ -2976,11 +2935,8 @@
 Ljava/lang/Daemons;->start()V
 Ljava/lang/Daemons;->stop()V
 Ljava/lang/Double;->value:D
-Ljava/lang/Enum;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/lang/Float;->value:F
 Ljava/lang/Integer;->value:I
-Ljava/lang/invoke/MethodType;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/lang/invoke/MethodType;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/lang/Long;->value:J
 Ljava/lang/ref/FinalizerReference;->add(Ljava/lang/Object;)V
 Ljava/lang/ref/FinalizerReference;->head:Ljava/lang/ref/FinalizerReference;
@@ -2996,10 +2952,6 @@
 Ljava/lang/Runtime;->load(Ljava/lang/String;Ljava/lang/ClassLoader;)V
 Ljava/lang/Runtime;->nativeLoad(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;
 Ljava/lang/Short;->value:S
-Ljava/lang/StringBuffer;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/lang/StringBuffer;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/lang/StringBuilder;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/lang/StringBuilder;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/lang/String;-><init>(II[C)V
 Ljava/lang/System;-><init>()V
 Ljava/lang/Thread;->daemon:Z
@@ -3023,16 +2975,9 @@
 Ljava/lang/Throwable;->cause:Ljava/lang/Throwable;
 Ljava/lang/Throwable;->detailMessage:Ljava/lang/String;
 Ljava/lang/Throwable;->nativeFillInStackTrace()Ljava/lang/Object;
-Ljava/lang/Throwable;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/lang/Throwable;->stackTrace:[Ljava/lang/StackTraceElement;
 Ljava/lang/Throwable;->suppressedExceptions:Ljava/util/List;
-Ljava/lang/Throwable;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/lang/Void;-><init>()V
-Ljava/math/BigDecimal;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/math/BigDecimal;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/math/BigInteger;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/math/BigInteger;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/math/MathContext;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/net/Authenticator;->theAuthenticator:Ljava/net/Authenticator;
 Ljava/net/DatagramSocket;->impl:Ljava/net/DatagramSocketImpl;
 Ljava/net/HttpCookie;->httpOnly:Z
@@ -3044,8 +2989,6 @@
 Ljava/net/Inet6Address$Inet6AddressHolder;->scope_id_set:Z
 Ljava/net/Inet6Address$Inet6AddressHolder;->scope_ifname:Ljava/net/NetworkInterface;
 Ljava/net/Inet6Address;-><init>()V
-Ljava/net/Inet6Address;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/net/Inet6Address;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/net/InetAddress;->clearDnsCache()V
 Ljava/net/InetAddress;->holder:Ljava/net/InetAddress$InetAddressHolder;
 Ljava/net/InetAddress$InetAddressHolder;->address:I
@@ -3054,19 +2997,11 @@
 Ljava/net/InetAddress$InetAddressHolder;->originalHostName:Ljava/lang/String;
 Ljava/net/InetAddress;->isNumeric(Ljava/lang/String;)Z
 Ljava/net/InetAddress;->parseNumericAddress(Ljava/lang/String;)Ljava/net/InetAddress;
-Ljava/net/InetAddress;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/net/InetAddress;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/net/InetSocketAddress;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/net/InetSocketAddress;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/net/Socket;->getFileDescriptor$()Ljava/io/FileDescriptor;
 Ljava/net/Socket;->impl:Ljava/net/SocketImpl;
 Ljava/net/URI;->host:Ljava/lang/String;
-Ljava/net/URI;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/net/URI;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/net/URL;->handler:Ljava/net/URLStreamHandler;
 Ljava/net/URL;->handlers:Ljava/util/Hashtable;
-Ljava/net/URL;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/net/URL;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/nio/Buffer;->address:J
 Ljava/nio/Buffer;->capacity:I
 Ljava/nio/Buffer;->_elementSizeShift:I
@@ -3077,168 +3012,37 @@
 Ljava/nio/ByteBuffer;->offset:I
 Ljava/nio/charset/CharsetEncoder;->canEncode(Ljava/nio/CharBuffer;)Z
 Ljava/nio/DirectByteBuffer;-><init>(JI)V
-Ljava/nio/file/DirectoryIteratorException;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/nio/NIOAccess;->getBaseArray(Ljava/nio/Buffer;)Ljava/lang/Object;
 Ljava/nio/NIOAccess;->getBaseArrayOffset(Ljava/nio/Buffer;)I
 Ljava/nio/NIOAccess;->getBasePointer(Ljava/nio/Buffer;)J
-Ljava/security/cert/CertificateRevokedException;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/security/cert/CertificateRevokedException;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/security/cert/CertPathValidatorException;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/security/CodeSigner;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/security/GuardedObject;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/security/Provider;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/security/SignedObject;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/security/spec/ECParameterSpec;->getCurveName()Ljava/lang/String;
 Ljava/security/spec/ECParameterSpec;->setCurveName(Ljava/lang/String;)V
-Ljava/security/Timestamp;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/ChoiceFormat;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/text/DateFormat;->is24Hour:Ljava/lang/Boolean;
-Ljava/text/DateFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/DateFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/text/DecimalFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/DecimalFormatSymbols;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/DecimalFormatSymbols;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/text/DecimalFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/text/MessageFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/NumberFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/text/NumberFormat;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/text/SimpleDateFormat;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/AbstractChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/HijrahChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/HijrahDate;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/IsoChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/JapaneseChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/JapaneseDate;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/JapaneseEra;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/MinguoChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/MinguoDate;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/ThaiBuddhistChronology;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/chrono/ThaiBuddhistDate;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/Duration;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/Duration;->toSeconds()Ljava/math/BigDecimal;
-Ljava/time/Instant;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/LocalDate;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/LocalDateTime;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/LocalTime;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/MonthDay;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/time/OffsetDateTime;-><init>(Ljava/time/LocalDateTime;Ljava/time/ZoneOffset;)V
-Ljava/time/OffsetDateTime;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/OffsetTime;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/Period;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/temporal/ValueRange;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/temporal/WeekFields;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/YearMonth;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/Year;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/ZonedDateTime;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/ZoneId;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/ZoneOffset;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/zone/ZoneOffsetTransition;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/zone/ZoneOffsetTransitionRule;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/time/zone/ZoneRules;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/ArrayDeque;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/ArrayDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/ArrayList;->elementData:[Ljava/lang/Object;
-Ljava/util/ArrayList;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/ArrayList;->size:I
 Ljava/util/ArrayList$SubList;->parent:Ljava/util/AbstractList;
 Ljava/util/ArrayList$SubList;->parentOffset:I
 Ljava/util/ArrayList$SubList;->size:I
-Ljava/util/ArrayList;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Arrays$ArrayList;->a:[Ljava/lang/Object;
-Ljava/util/BitSet;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/BitSet;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/Calendar;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/Calendar;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Calendar;->zone:Ljava/util/TimeZone;
 Ljava/util/Collections$EmptyList;-><init>()V
-Ljava/util/Collections$SetFromMap;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/Collections$SynchronizedCollection;->c:Ljava/util/Collection;
-Ljava/util/Collections$SynchronizedCollection;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Collections$SynchronizedMap;->m:Ljava/util/Map;
-Ljava/util/Collections$SynchronizedMap;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Collections$UnmodifiableCollection;->c:Ljava/util/Collection;
 Ljava/util/Collections$UnmodifiableMap;->m:Ljava/util/Map;
-Ljava/util/concurrent/atomic/AtomicReferenceArray;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/atomic/DoubleAccumulator;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/atomic/DoubleAdder;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/atomic/LongAccumulator;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/atomic/LongAdder;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/concurrent/ConcurrentHashMap$BaseIterator;->hasMoreElements()Z
-Ljava/util/concurrent/ConcurrentHashMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/ConcurrentHashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/ConcurrentLinkedDeque;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/ConcurrentLinkedDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/ConcurrentLinkedQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/ConcurrentLinkedQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/ConcurrentSkipListMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/ConcurrentSkipListMap;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/CopyOnWriteArrayList;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/CopyOnWriteArrayList;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/ForkJoinTask;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/ForkJoinTask;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/concurrent/FutureTask;->callable:Ljava/util/concurrent/Callable;
-Ljava/util/concurrent/LinkedBlockingDeque;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/LinkedBlockingDeque;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/concurrent/LinkedBlockingQueue;->capacity:I
-Ljava/util/concurrent/LinkedBlockingQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/LinkedBlockingQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/LinkedTransferQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/LinkedTransferQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/locks/ReentrantLock$Sync;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/locks/ReentrantReadWriteLock$Sync;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/locks/StampedLock;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/PriorityBlockingQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/PriorityBlockingQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/SynchronousQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/concurrent/SynchronousQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/concurrent/ThreadLocalRandom;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/Date;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/Date;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/EnumMap;->keyType:Ljava/lang/Class;
-Ljava/util/EnumMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/EnumMap;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/EnumSet;->elementType:Ljava/lang/Class;
-Ljava/util/EnumSet;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/GregorianCalendar;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/HashMap$HashIterator;->hasNext()Z
-Ljava/util/HashMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/HashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/HashSet;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/HashSet;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/Hashtable;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/Hashtable;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/IdentityHashMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/IdentityHashMap;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/InvalidPropertiesFormatException;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/InvalidPropertiesFormatException;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/LinkedHashMap;->eldest()Ljava/util/Map$Entry;
 Ljava/util/LinkedHashMap$LinkedHashIterator;->hasNext()Z
-Ljava/util/LinkedList;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/LinkedList;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Locale;->createConstant(Ljava/lang/String;Ljava/lang/String;)Ljava/util/Locale;
-Ljava/util/Locale;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/Locale;->readResolve()Ljava/lang/Object;
-Ljava/util/Locale;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/logging/LogRecord;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/logging/LogRecord;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/prefs/NodeChangeEvent;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/prefs/NodeChangeEvent;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/prefs/PreferenceChangeEvent;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/prefs/PreferenceChangeEvent;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/PriorityQueue;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/PriorityQueue;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/Random;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/Random;->seedUniquifier()J
-Ljava/util/Random;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/regex/Matcher;->appendPos:I
-Ljava/util/regex/Pattern;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/SimpleTimeZone;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/SimpleTimeZone;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/TreeMap;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/TreeMap;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/TreeSet;->readObject(Ljava/io/ObjectInputStream;)V
-Ljava/util/TreeSet;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljava/util/Vector;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/zip/Deflater;->buf:[B
 Ljava/util/zip/Deflater;->finished:Z
 Ljava/util/zip/Deflater;->finish:Z
@@ -3254,23 +3058,11 @@
 Ljava/util/zip/Inflater;->off:I
 Ljava/util/zip/ZipEntry;-><init>(Ljava/lang/String;Ljava/lang/String;JJJII[BJ)V
 Ljava/util/zip/ZipFile;->jzfile:J
-Ljavax/crypto/SealedObject;->readObject(Ljava/io/ObjectInputStream;)V
 Ljavax/net/ssl/SSLServerSocketFactory;->defaultServerSocketFactory:Ljavax/net/ssl/SSLServerSocketFactory;
 Ljavax/net/ssl/SSLSocketFactory;->defaultSocketFactory:Ljavax/net/ssl/SSLSocketFactory;
-Ljavax/security/auth/Subject;->readObject(Ljava/io/ObjectInputStream;)V
-Ljavax/security/auth/Subject$SecureSet;->readObject(Ljava/io/ObjectInputStream;)V
-Ljavax/security/auth/Subject$SecureSet;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljavax/security/auth/Subject;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljavax/security/auth/x500/X500Principal;->readObject(Ljava/io/ObjectInputStream;)V
-Ljavax/security/auth/x500/X500Principal;->writeObject(Ljava/io/ObjectOutputStream;)V
-Ljavax/xml/datatype/DatatypeConfigurationException;->readObject(Ljava/io/ObjectInputStream;)V
-Ljavax/xml/namespace/QName;->readObject(Ljava/io/ObjectInputStream;)V
 Llibcore/util/ZoneInfo;->mTransitions:[J
-Llibcore/util/ZoneInfo;->readObject(Ljava/io/ObjectInputStream;)V
 Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>(Ljavax/net/ssl/SSLSocketFactory;)V
 Lorg/apache/http/conn/ssl/SSLSocketFactory;-><init>()V
 Lorg/json/JSONArray;->values:Ljava/util/List;
 Lorg/json/JSONObject;->writeTo(Lorg/json/JSONStringer;)V
 Lsun/misc/Unsafe;->theUnsafe:Lsun/misc/Unsafe;
-Lsun/security/util/ObjectIdentifier;->readObject(Ljava/io/ObjectInputStream;)V
-Lsun/security/util/ObjectIdentifier;->writeObject(Ljava/io/ObjectOutputStream;)V
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index ee13880..02afcc7 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -65,7 +65,6 @@
             NETWORK_TYPE_UNMETERED,
             NETWORK_TYPE_NOT_ROAMING,
             NETWORK_TYPE_CELLULAR,
-            NETWORK_TYPE_METERED,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface NetworkType {}
@@ -253,7 +252,7 @@
     /**
      * @hide
      */
-    public static final int FLAG_IS_PREFETCH = 1 << 2;
+    public static final int FLAG_PREFETCH = 1 << 2;
 
     /**
      * This job needs to be exempted from the app standby throttling. Only the system (UID 1000)
@@ -296,7 +295,8 @@
     private final boolean hasEarlyConstraint;
     private final boolean hasLateConstraint;
     private final NetworkRequest networkRequest;
-    private final long networkBytes;
+    private final long networkDownloadBytes;
+    private final long networkUploadBytes;
     private final long minLatencyMillis;
     private final long maxExecutionDelayMillis;
     private final boolean isPeriodic;
@@ -317,30 +317,28 @@
     }
 
     /**
-     * Bundle of extras which are returned to your application at execution time.
+     * @see JobInfo.Builder#setExtras(PersistableBundle)
      */
     public @NonNull PersistableBundle getExtras() {
         return extras;
     }
 
     /**
-     * Bundle of transient extras which are returned to your application at execution time,
-     * but not persisted by the system.
+     * @see JobInfo.Builder#setTransientExtras(Bundle)
      */
     public @NonNull Bundle getTransientExtras() {
         return transientExtras;
     }
 
     /**
-     * ClipData of information that is returned to your application at execution time,
-     * but not persisted by the system.
+     * @see JobInfo.Builder#setClipData(ClipData, int)
      */
     public @Nullable ClipData getClipData() {
         return clipData;
     }
 
     /**
-     * Permission grants that go along with {@link #getClipData}.
+     * @see JobInfo.Builder#setClipData(ClipData, int)
      */
     public int getClipGrantFlags() {
         return clipGrantFlags;
@@ -369,32 +367,28 @@
     }
 
     /**
-     * Whether this job requires that the device be charging (or be a non-battery-powered
-     * device connected to permanent power, such as Android TV devices).
+     * @see JobInfo.Builder#setRequiresCharging(boolean)
      */
     public boolean isRequireCharging() {
         return (constraintFlags & CONSTRAINT_FLAG_CHARGING) != 0;
     }
 
     /**
-     * Whether this job needs the device's battery level to not be at below the critical threshold.
+     * @see JobInfo.Builder#setRequiresBatteryNotLow(boolean)
      */
     public boolean isRequireBatteryNotLow() {
         return (constraintFlags & CONSTRAINT_FLAG_BATTERY_NOT_LOW) != 0;
     }
 
     /**
-     * Whether this job requires that the user <em>not</em> be interacting with the device.
-     *
-     * <p class="note">This is <em>not</em> the same as "doze" or "device idle";
-     * it is purely about the user's direct interactions.</p>
+     * @see JobInfo.Builder#setRequiresDeviceIdle(boolean)
      */
     public boolean isRequireDeviceIdle() {
         return (constraintFlags & CONSTRAINT_FLAG_DEVICE_IDLE) != 0;
     }
 
     /**
-     * Whether this job needs the device's storage to not be low.
+     * @see JobInfo.Builder#setRequiresStorageNotLow(boolean)
      */
     public boolean isRequireStorageNotLow() {
         return (constraintFlags & CONSTRAINT_FLAG_STORAGE_NOT_LOW) != 0;
@@ -410,6 +404,7 @@
     /**
      * Which content: URIs must change for the job to be scheduled.  Returns null
      * if there are none required.
+     * @see JobInfo.Builder#addTriggerContentUri(TriggerContentUri)
      */
     public @Nullable TriggerContentUri[] getTriggerContentUris() {
         return triggerContentUris;
@@ -418,6 +413,7 @@
     /**
      * When triggering on content URI changes, this is the delay from when a change
      * is detected until the job is scheduled.
+     * @see JobInfo.Builder#setTriggerContentUpdateDelay(long)
      */
     public long getTriggerContentUpdateDelay() {
         return triggerContentUpdateDelay;
@@ -426,6 +422,7 @@
     /**
      * When triggering on content URI changes, this is the maximum delay we will
      * use before scheduling the job.
+     * @see JobInfo.Builder#setTriggerContentMaxDelay(long)
      */
     public long getTriggerContentMaxDelay() {
         return triggerContentMaxDelay;
@@ -466,28 +463,59 @@
     }
 
     /**
-     * Return the estimated size of network traffic that will be performed by
+     * @deprecated replaced by {@link #getEstimatedNetworkDownloadBytes()} and
+     *             {@link #getEstimatedNetworkUploadBytes()}.
+     * @removed
+     */
+    @Deprecated
+    public @BytesLong long getEstimatedNetworkBytes() {
+        if (networkDownloadBytes == NETWORK_BYTES_UNKNOWN
+                && networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
+            return NETWORK_BYTES_UNKNOWN;
+        } else if (networkDownloadBytes == NETWORK_BYTES_UNKNOWN) {
+            return networkUploadBytes;
+        } else if (networkUploadBytes == NETWORK_BYTES_UNKNOWN) {
+            return networkDownloadBytes;
+        } else {
+            return networkDownloadBytes + networkUploadBytes;
+        }
+    }
+
+    /**
+     * Return the estimated size of download traffic that will be performed by
      * this job, in bytes.
      *
-     * @return Estimated size of network traffic, or
+     * @return Estimated size of download traffic, or
      *         {@link #NETWORK_BYTES_UNKNOWN} when unknown.
-     * @see Builder#setEstimatedNetworkBytes(long)
+     * @see Builder#setEstimatedNetworkBytes(long, long)
      */
-    public @BytesLong long getEstimatedNetworkBytes() {
-        return networkBytes;
+    public @BytesLong long getEstimatedNetworkDownloadBytes() {
+        return networkDownloadBytes;
+    }
+
+    /**
+     * Return the estimated size of upload traffic that will be performed by
+     * this job, in bytes.
+     *
+     * @return Estimated size of upload traffic, or
+     *         {@link #NETWORK_BYTES_UNKNOWN} when unknown.
+     * @see Builder#setEstimatedNetworkBytes(long, long)
+     */
+    public @BytesLong long getEstimatedNetworkUploadBytes() {
+        return networkUploadBytes;
     }
 
     /**
      * Set for a job that does not recur periodically, to specify a delay after which the job
      * will be eligible for execution. This value is not set if the job recurs periodically.
+     * @see JobInfo.Builder#setMinimumLatency(long)
      */
     public long getMinLatencyMillis() {
         return minLatencyMillis;
     }
 
     /**
-     * See {@link Builder#setOverrideDeadline(long)}. This value is not set if the job recurs
-     * periodically.
+     * @see JobInfo.Builder#setOverrideDeadline(long)
      */
     public long getMaxExecutionDelayMillis() {
         return maxExecutionDelayMillis;
@@ -495,13 +523,15 @@
 
     /**
      * Track whether this job will repeat with a given period.
+     * @see JobInfo.Builder#setPeriodic(long)
+     * @see JobInfo.Builder#setPeriodic(long, long)
      */
     public boolean isPeriodic() {
         return isPeriodic;
     }
 
     /**
-     * @return Whether or not this job should be persisted across device reboots.
+     * @see JobInfo.Builder#setPersisted(boolean)
      */
     public boolean isPersisted() {
         return isPersisted;
@@ -510,6 +540,8 @@
     /**
      * Set to the interval between occurrences of this job. This value is <b>not</b> set if the
      * job does not recur periodically.
+     * @see JobInfo.Builder#setPeriodic(long)
+     * @see JobInfo.Builder#setPeriodic(long, long)
      */
     public long getIntervalMillis() {
         return intervalMillis;
@@ -518,6 +550,8 @@
     /**
      * Flex time for this job. Only valid if this is a periodic job.  The job can
      * execute at any time in a window of flex length at the end of the period.
+     * @see JobInfo.Builder#setPeriodic(long)
+     * @see JobInfo.Builder#setPeriodic(long, long)
      */
     public long getFlexMillis() {
         return flexMillis;
@@ -527,6 +561,7 @@
      * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
      * will be increased depending on the backoff policy specified at job creation time. Defaults
      * to 30 seconds, minimum is currently 10 seconds.
+     * @see JobInfo.Builder#setBackoffCriteria(long, int)
      */
     public long getInitialBackoffMillis() {
         return initialBackoffMillis;
@@ -534,12 +569,27 @@
 
     /**
      * Return the backoff policy of this job.
+     * @see JobInfo.Builder#setBackoffCriteria(long, int)
      */
     public @BackoffPolicy int getBackoffPolicy() {
         return backoffPolicy;
     }
 
     /**
+     * @see JobInfo.Builder#setImportantWhileForeground(boolean)
+     */
+    public boolean isImportantWhileForeground() {
+        return (flags & FLAG_IMPORTANT_WHILE_FOREGROUND) != 0;
+    }
+
+    /**
+     * @see JobInfo.Builder#setPrefetch(boolean)
+     */
+    public boolean isPrefetch() {
+        return (flags & FLAG_PREFETCH) != 0;
+    }
+
+    /**
      * User can specify an early constraint of 0L, which is valid, so we keep track of whether the
      * function was called at all.
      * @hide
@@ -610,7 +660,10 @@
         if (!Objects.equals(networkRequest, j.networkRequest)) {
             return false;
         }
-        if (networkBytes != j.networkBytes) {
+        if (networkDownloadBytes != j.networkDownloadBytes) {
+            return false;
+        }
+        if (networkUploadBytes != j.networkUploadBytes) {
             return false;
         }
         if (minLatencyMillis != j.minLatencyMillis) {
@@ -673,7 +726,8 @@
         if (networkRequest != null) {
             hashCode = 31 * hashCode + networkRequest.hashCode();
         }
-        hashCode = 31 * hashCode + Long.hashCode(networkBytes);
+        hashCode = 31 * hashCode + Long.hashCode(networkDownloadBytes);
+        hashCode = 31 * hashCode + Long.hashCode(networkUploadBytes);
         hashCode = 31 * hashCode + Long.hashCode(minLatencyMillis);
         hashCode = 31 * hashCode + Long.hashCode(maxExecutionDelayMillis);
         hashCode = 31 * hashCode + Boolean.hashCode(isPeriodic);
@@ -708,7 +762,8 @@
         } else {
             networkRequest = null;
         }
-        networkBytes = in.readLong();
+        networkDownloadBytes = in.readLong();
+        networkUploadBytes = in.readLong();
         minLatencyMillis = in.readLong();
         maxExecutionDelayMillis = in.readLong();
         isPeriodic = in.readInt() == 1;
@@ -737,7 +792,8 @@
         triggerContentUpdateDelay = b.mTriggerContentUpdateDelay;
         triggerContentMaxDelay = b.mTriggerContentMaxDelay;
         networkRequest = b.mNetworkRequest;
-        networkBytes = b.mNetworkBytes;
+        networkDownloadBytes = b.mNetworkDownloadBytes;
+        networkUploadBytes = b.mNetworkUploadBytes;
         minLatencyMillis = b.mMinLatencyMillis;
         maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
         isPeriodic = b.mIsPeriodic;
@@ -780,7 +836,8 @@
         } else {
             out.writeInt(0);
         }
-        out.writeLong(networkBytes);
+        out.writeLong(networkDownloadBytes);
+        out.writeLong(networkUploadBytes);
         out.writeLong(minLatencyMillis);
         out.writeLong(maxExecutionDelayMillis);
         out.writeInt(isPeriodic ? 1 : 0);
@@ -914,7 +971,8 @@
         // Requirements.
         private int mConstraintFlags;
         private NetworkRequest mNetworkRequest;
-        private long mNetworkBytes = NETWORK_BYTES_UNKNOWN;
+        private long mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN;
+        private long mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN;
         private ArrayList<TriggerContentUri> mTriggerContentUris;
         private long mTriggerContentUpdateDelay = -1;
         private long mTriggerContentMaxDelay = -1;
@@ -965,6 +1023,7 @@
         /**
          * Set optional extras. This is persisted, so we only allow primitive types.
          * @param extras Bundle containing extras you want the scheduler to hold on to for you.
+         * @see JobInfo#getExtras()
          */
         public Builder setExtras(@NonNull PersistableBundle extras) {
             mExtras = extras;
@@ -979,6 +1038,7 @@
          * {@link android.app.job.JobInfo.Builder#build()} is called.</p>
          *
          * @param extras Bundle containing extras you want the scheduler to hold on to for you.
+         * @see JobInfo#getTransientExtras()
          */
         public Builder setTransientExtras(@NonNull Bundle extras) {
             mTransientExtras = extras;
@@ -1006,6 +1066,8 @@
          * a combination of {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION},
          * {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION}, and
          * {@link android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION}.
+         * @see JobInfo#getClipData()
+         * @see JobInfo#getClipGrantFlags()
          */
         public Builder setClipData(@Nullable ClipData clip, int grantFlags) {
             mClipData = clip;
@@ -1096,6 +1158,16 @@
         }
 
         /**
+         * @deprecated replaced by
+         *             {@link #setEstimatedNetworkBytes(long, long)}.
+         * @removed
+         */
+        @Deprecated
+        public Builder setEstimatedNetworkBytes(@BytesLong long networkBytes) {
+            return setEstimatedNetworkBytes(networkBytes, NETWORK_BYTES_UNKNOWN);
+        }
+
+        /**
          * Set the estimated size of network traffic that will be performed by
          * this job, in bytes.
          * <p>
@@ -1112,23 +1184,30 @@
          * <li>A job that synchronizes email could end up using an extreme range
          * of data, from under 1KB when nothing has changed, to dozens of MB
          * when there are new emails with attachments. Jobs that cannot provide
-         * reasonable estimates should leave this estimated value undefined.
+         * reasonable estimates should use the sentinel value
+         * {@link JobInfo#NETWORK_BYTES_UNKNOWN}.
          * </ul>
          * Note that the system may choose to delay jobs with large network
          * usage estimates when the device has a poor network connection, in
          * order to save battery.
+         * <p>
+         * The values provided here only reflect the traffic that will be
+         * performed by the base job; if you're using {@link JobWorkItem} then
+         * you also need to define the network traffic used by each work item
+         * when constructing them.
          *
-         * @param networkBytes The estimated size of network traffic that will
-         *            be performed by this job, in bytes. This value only
-         *            reflects the traffic that will be performed by the base
-         *            job; if you're using {@link JobWorkItem} then you also
-         *            need to define the network traffic used by each work item
-         *            when constructing them.
-         * @see JobInfo#getEstimatedNetworkBytes()
-         * @see JobWorkItem#JobWorkItem(android.content.Intent, long)
+         * @param downloadBytes The estimated size of network traffic that will
+         *            be downloaded by this job, in bytes.
+         * @param uploadBytes The estimated size of network traffic that will be
+         *            uploaded by this job, in bytes.
+         * @see JobInfo#getEstimatedNetworkDownloadBytes()
+         * @see JobInfo#getEstimatedNetworkUploadBytes()
+         * @see JobWorkItem#JobWorkItem(android.content.Intent, long, long)
          */
-        public Builder setEstimatedNetworkBytes(@BytesLong long networkBytes) {
-            mNetworkBytes = networkBytes;
+        public Builder setEstimatedNetworkBytes(@BytesLong long downloadBytes,
+                @BytesLong long uploadBytes) {
+            mNetworkDownloadBytes = downloadBytes;
+            mNetworkUploadBytes = uploadBytes;
             return this;
         }
 
@@ -1146,6 +1225,7 @@
          *
          * @param requiresCharging Pass {@code true} to require that the device be
          *     charging in order to run the job.
+         * @see JobInfo#isRequireCharging()
          */
         public Builder setRequiresCharging(boolean requiresCharging) {
             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_CHARGING)
@@ -1159,6 +1239,7 @@
          * is not low, which is generally the point where the user is given a "low battery"
          * warning.
          * @param batteryNotLow Whether or not the device's battery level must not be low.
+         * @see JobInfo#isRequireBatteryNotLow()
          */
         public Builder setRequiresBatteryNotLow(boolean batteryNotLow) {
             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_BATTERY_NOT_LOW)
@@ -1183,6 +1264,7 @@
          *
          * @param requiresDeviceIdle Pass {@code true} to prevent the job from running
          *     while the device is being used interactively.
+         * @see JobInfo#isRequireDeviceIdle()
          */
         public Builder setRequiresDeviceIdle(boolean requiresDeviceIdle) {
             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_DEVICE_IDLE)
@@ -1196,6 +1278,7 @@
          * in a low storage state, which is generally the point where the user is given a
          * "low storage" warning.
          * @param storageNotLow Whether or not the device's available storage must not be low.
+         * @see JobInfo#isRequireStorageNotLow()
          */
         public Builder setRequiresStorageNotLow(boolean storageNotLow) {
             mConstraintFlags = (mConstraintFlags&~CONSTRAINT_FLAG_STORAGE_NOT_LOW)
@@ -1228,6 +1311,7 @@
          *      job}
          *
          * @param uri The content: URI to monitor.
+         * @see JobInfo#getTriggerContentUris()
          */
         public Builder addTriggerContentUri(@NonNull TriggerContentUri uri) {
             if (mTriggerContentUris == null) {
@@ -1242,6 +1326,7 @@
          * the job is scheduled.  If there are more changes during that time, the delay
          * will be reset to start at the time of the most recent change.
          * @param durationMs Delay after most recent content change, in milliseconds.
+         * @see JobInfo#getTriggerContentUpdateDelay()
          */
         public Builder setTriggerContentUpdateDelay(long durationMs) {
             mTriggerContentUpdateDelay = durationMs;
@@ -1252,6 +1337,7 @@
          * Set the maximum total delay (in milliseconds) that is allowed from the first
          * time a content change is detected until the job is scheduled.
          * @param durationMs Delay after initial content change, in milliseconds.
+         * @see JobInfo#getTriggerContentMaxDelay()
          */
         public Builder setTriggerContentMaxDelay(long durationMs) {
             mTriggerContentMaxDelay = durationMs;
@@ -1265,6 +1351,8 @@
          * Setting this function on the builder with {@link #setMinimumLatency(long)} or
          * {@link #setOverrideDeadline(long)} will result in an error.
          * @param intervalMillis Millisecond interval for which this job will repeat.
+         * @see JobInfo#getIntervalMillis()
+         * @see JobInfo#getFlexMillis()
          */
         public Builder setPeriodic(long intervalMillis) {
             return setPeriodic(intervalMillis, intervalMillis);
@@ -1278,6 +1366,8 @@
          * @param flexMillis Millisecond flex for this job. Flex is clamped to be at least
          *                   {@link #getMinFlexMillis()} or 5 percent of the period, whichever is
          *                   higher.
+         * @see JobInfo#getIntervalMillis()
+         * @see JobInfo#getFlexMillis()
          */
         public Builder setPeriodic(long intervalMillis, long flexMillis) {
             final long minPeriod = getMinPeriodMillis();
@@ -1309,6 +1399,7 @@
          * {@link android.app.job.JobInfo.Builder#build()} is called.
          * @param minLatencyMillis Milliseconds before which this job will not be considered for
          *                         execution.
+         * @see JobInfo#getMinLatencyMillis()
          */
         public Builder setMinimumLatency(long minLatencyMillis) {
             mMinLatencyMillis = minLatencyMillis;
@@ -1322,6 +1413,7 @@
          * this property on a periodic job, doing so will throw an
          * {@link java.lang.IllegalArgumentException} when
          * {@link android.app.job.JobInfo.Builder#build()} is called.
+         * @see JobInfo#getMaxExecutionDelayMillis()
          */
         public Builder setOverrideDeadline(long maxExecutionDelayMillis) {
             mMaxExecutionDelayMillis = maxExecutionDelayMillis;
@@ -1341,6 +1433,8 @@
          * mode.
          * @param initialBackoffMillis Millisecond time interval to wait initially when job has
          *                             failed.
+         * @see JobInfo#getInitialBackoffMillis()
+         * @see JobInfo#getBackoffPolicy()
          */
         public Builder setBackoffCriteria(long initialBackoffMillis,
                 @BackoffPolicy int backoffPolicy) {
@@ -1371,6 +1465,7 @@
          *
          * @param importantWhileForeground whether to relax doze restrictions for this job when the
          *                                 app is in the foreground. False by default.
+         * @see JobInfo#isImportantWhileForeground()
          */
         public Builder setImportantWhileForeground(boolean importantWhileForeground) {
             if (importantWhileForeground) {
@@ -1382,6 +1477,15 @@
         }
 
         /**
+         * @removed
+         * @deprecated replaced with {@link #setPrefetch(boolean)}
+         */
+        @Deprecated
+        public Builder setIsPrefetch(boolean isPrefetch) {
+            return setPrefetch(isPrefetch);
+        }
+
+        /**
          * Setting this to true indicates that this job is designed to prefetch
          * content that will make a material improvement to the experience of
          * the specific user of this device. For example, fetching top headlines
@@ -1393,12 +1497,13 @@
          * network when there is a surplus of metered data available. The system
          * may also use this signal in combination with end user usage patterns
          * to ensure data is prefetched before the user launches your app.
+         * @see JobInfo#isPrefetch()
          */
-        public Builder setIsPrefetch(boolean isPrefetch) {
-            if (isPrefetch) {
-                mFlags |= FLAG_IS_PREFETCH;
+        public Builder setPrefetch(boolean prefetch) {
+            if (prefetch) {
+                mFlags |= FLAG_PREFETCH;
             } else {
-                mFlags &= (~FLAG_IS_PREFETCH);
+                mFlags &= (~FLAG_PREFETCH);
             }
             return this;
         }
@@ -1408,6 +1513,7 @@
          *
          * @param isPersisted True to indicate that the job will be written to
          *            disk and loaded at boot.
+         * @see JobInfo#isPersisted()
          */
         @RequiresPermission(android.Manifest.permission.RECEIVE_BOOT_COMPLETED)
         public Builder setPersisted(boolean isPersisted) {
@@ -1427,7 +1533,7 @@
                         "constraints, this is not allowed.");
             }
             // Check that network estimates require network type
-            if (mNetworkBytes > 0 && mNetworkRequest == null) {
+            if ((mNetworkDownloadBytes > 0 || mNetworkUploadBytes > 0) && mNetworkRequest == null) {
                 throw new IllegalArgumentException(
                         "Can't provide estimated network usage without requiring a network");
             }
diff --git a/core/java/android/app/job/JobWorkItem.java b/core/java/android/app/job/JobWorkItem.java
index 1c46e8e..995f522 100644
--- a/core/java/android/app/job/JobWorkItem.java
+++ b/core/java/android/app/job/JobWorkItem.java
@@ -16,6 +16,8 @@
 
 package android.app.job;
 
+import static android.app.job.JobInfo.NETWORK_BYTES_UNKNOWN;
+
 import android.annotation.BytesLong;
 import android.content.Intent;
 import android.os.Parcel;
@@ -28,7 +30,8 @@
  */
 final public class JobWorkItem implements Parcelable {
     final Intent mIntent;
-    final long mNetworkBytes;
+    final long mNetworkDownloadBytes;
+    final long mNetworkUploadBytes;
     int mDeliveryCount;
     int mWorkId;
     Object mGrants;
@@ -41,22 +44,36 @@
      */
     public JobWorkItem(Intent intent) {
         mIntent = intent;
-        mNetworkBytes = JobInfo.NETWORK_BYTES_UNKNOWN;
+        mNetworkDownloadBytes = NETWORK_BYTES_UNKNOWN;
+        mNetworkUploadBytes = NETWORK_BYTES_UNKNOWN;
+    }
+
+    /**
+     * @deprecated replaced by {@link #JobWorkItem(Intent, long, long)}
+     * @removed
+     */
+    @Deprecated
+    public JobWorkItem(Intent intent, @BytesLong long networkBytes) {
+        this(intent, networkBytes, NETWORK_BYTES_UNKNOWN);
     }
 
     /**
      * Create a new piece of work, which can be submitted to
      * {@link JobScheduler#enqueue JobScheduler.enqueue}.
+     * <p>
+     * See {@link JobInfo.Builder#setEstimatedNetworkBytes(long, long)} for
+     * details about how to estimate network traffic.
      *
      * @param intent The general Intent describing this work.
-     * @param networkBytes The estimated size of network traffic that will be
-     *            performed by this job work item, in bytes. See
-     *            {@link JobInfo.Builder#setEstimatedNetworkBytes(long)} for
-     *            details about how to estimate.
+     * @param downloadBytes The estimated size of network traffic that will be
+     *            downloaded by this job work item, in bytes.
+     * @param uploadBytes The estimated size of network traffic that will be
+     *            uploaded by this job work item, in bytes.
      */
-    public JobWorkItem(Intent intent, @BytesLong long networkBytes) {
+    public JobWorkItem(Intent intent, @BytesLong long downloadBytes, @BytesLong long uploadBytes) {
         mIntent = intent;
-        mNetworkBytes = networkBytes;
+        mNetworkDownloadBytes = downloadBytes;
+        mNetworkUploadBytes = uploadBytes;
     }
 
     /**
@@ -67,14 +84,44 @@
     }
 
     /**
-     * Return the estimated size of network traffic that will be performed by
+     * @deprecated replaced by {@link #getEstimatedNetworkDownloadBytes()} and
+     *             {@link #getEstimatedNetworkUploadBytes()}.
+     * @removed
+     */
+    @Deprecated
+    public @BytesLong long getEstimatedNetworkBytes() {
+        if (mNetworkDownloadBytes == NETWORK_BYTES_UNKNOWN
+                && mNetworkUploadBytes == NETWORK_BYTES_UNKNOWN) {
+            return NETWORK_BYTES_UNKNOWN;
+        } else if (mNetworkDownloadBytes == NETWORK_BYTES_UNKNOWN) {
+            return mNetworkUploadBytes;
+        } else if (mNetworkUploadBytes == NETWORK_BYTES_UNKNOWN) {
+            return mNetworkDownloadBytes;
+        } else {
+            return mNetworkDownloadBytes + mNetworkUploadBytes;
+        }
+    }
+
+    /**
+     * Return the estimated size of download traffic that will be performed by
+     * this job, in bytes.
+     *
+     * @return Estimated size of download traffic, or
+     *         {@link JobInfo#NETWORK_BYTES_UNKNOWN} when unknown.
+     */
+    public @BytesLong long getEstimatedNetworkDownloadBytes() {
+        return mNetworkDownloadBytes;
+    }
+
+    /**
+     * Return the estimated size of upload traffic that will be performed by
      * this job work item, in bytes.
      *
-     * @return estimated size, or {@link JobInfo#NETWORK_BYTES_UNKNOWN} when
-     *         unknown.
+     * @return Estimated size of upload traffic, or
+     *         {@link JobInfo#NETWORK_BYTES_UNKNOWN} when unknown.
      */
-    public @BytesLong long getEstimatedNetworkBytes() {
-        return mNetworkBytes;
+    public @BytesLong long getEstimatedNetworkUploadBytes() {
+        return mNetworkUploadBytes;
     }
 
     /**
@@ -128,9 +175,13 @@
         sb.append(mWorkId);
         sb.append(" intent=");
         sb.append(mIntent);
-        if (mNetworkBytes != JobInfo.NETWORK_BYTES_UNKNOWN) {
-            sb.append(" networkBytes=");
-            sb.append(mNetworkBytes);
+        if (mNetworkDownloadBytes != NETWORK_BYTES_UNKNOWN) {
+            sb.append(" downloadBytes=");
+            sb.append(mNetworkDownloadBytes);
+        }
+        if (mNetworkUploadBytes != NETWORK_BYTES_UNKNOWN) {
+            sb.append(" uploadBytes=");
+            sb.append(mNetworkUploadBytes);
         }
         if (mDeliveryCount != 0) {
             sb.append(" dcount=");
@@ -151,7 +202,8 @@
         } else {
             out.writeInt(0);
         }
-        out.writeLong(mNetworkBytes);
+        out.writeLong(mNetworkDownloadBytes);
+        out.writeLong(mNetworkUploadBytes);
         out.writeInt(mDeliveryCount);
         out.writeInt(mWorkId);
     }
@@ -173,7 +225,8 @@
         } else {
             mIntent = null;
         }
-        mNetworkBytes = in.readLong();
+        mNetworkDownloadBytes = in.readLong();
+        mNetworkUploadBytes = in.readLong();
         mDeliveryCount = in.readInt();
         mWorkId = in.readInt();
     }
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 55c17b9..b5e223c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1340,6 +1340,30 @@
     <integer-array name="config_autoBrightnessKeyboardBacklightValues">
     </integer-array>
 
+    <!-- Array of light sensor lux values to define the minimum brightness curve, which guarantees
+         that any curve that dips below it is rejected by the system.
+         This prevents auto-brightness from setting the screen so dark as to prevent the user from
+         disabling auto-brightness or reseting the brightness curve via ADB.
+
+         The control points must be strictly increasing. Each control point corresponds to an entry
+         in the minimum brightness nits array. -->
+    <integer-array name="config_autoBrightnessMinimumBrightnessCurveLux">
+        <item>2000</item>
+        <item>4000</item>
+    </integer-array>
+
+    <!-- Array of desired screen brightness in nits corresponding to the lux values
+         in the config_autoBrightnessMinimumBrightnessCurveLux array.
+
+         This array should have size one greater than the size of the
+         config_autoBrightnessMinimumBrightnessCurveLux array. The values must be non-negative and
+         non-decreasing. -->
+    <array name="config_autoBrightnessMinimumBrightnessCurveNits">
+        <item>1.0</item>
+        <item>50.0</item>
+        <item>90.0</item>
+    </array>
+
     <!-- Array of hysteresis constraint values for brightening, represented as tenths of a
          percent. The length of this array is assumed to be one greater than
          config_dynamicHysteresisLuxLevels. The brightening threshold is calculated as
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 75f8013..5eeb418 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1794,6 +1794,8 @@
   <java-symbol type="array" name="config_autoBrightnessKeyboardBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessLcdBacklightValues" />
   <java-symbol type="array" name="config_autoBrightnessLevels" />
+  <java-symbol type="array" name="config_autoBrightnessMinimumBrightnessCurveLux" />
+  <java-symbol type="array" name="config_autoBrightnessMinimumBrightnessCurveNits" />
   <java-symbol type="array" name="config_dynamicHysteresisBrightLevels" />
   <java-symbol type="array" name="config_dynamicHysteresisDarkLevels" />
   <java-symbol type="array" name="config_dynamicHysteresisLuxLevels" />
diff --git a/data/etc/hiddenapi-package-whitelist.xml b/data/etc/hiddenapi-package-whitelist.xml
index bacddf14..a4a1b94 100644
--- a/data/etc/hiddenapi-package-whitelist.xml
+++ b/data/etc/hiddenapi-package-whitelist.xml
@@ -64,6 +64,7 @@
   <hidden-api-whitelisted-app package="com.android.gallery" />
   <hidden-api-whitelisted-app package="com.android.hotspot2" />
   <hidden-api-whitelisted-app package="com.android.keychain" />
+  <hidden-api-whitelisted-app package="com.android.launcher3" />
   <hidden-api-whitelisted-app package="com.android.location.fused" />
   <hidden-api-whitelisted-app package="com.android.managedprovisioning" />
   <hidden-api-whitelisted-app package="com.android.mms.service" />
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index e37ca1c..c59492f 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -24,6 +24,8 @@
 
     <dimen name="brightness_mirror_height">96dp</dimen>
 
+    <!-- Width for the spacer, used between QS tiles. -->
+    <dimen name="qs_quick_tile_space_width">38dp</dimen>
     <dimen name="qs_tile_margin_top">2dp</dimen>
     <dimen name="qs_header_tooltip_height">24dp</dimen>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index ff3f696..91c8724 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -317,6 +317,8 @@
     <dimen name="qs_tile_margin_vertical">24dp</dimen>
     <dimen name="qs_tile_margin_top">18dp</dimen>
     <dimen name="qs_quick_tile_size">48dp</dimen>
+    <!-- Width for the spacer, used between QS tiles. -->
+    <dimen name="qs_quick_tile_space_width">0dp</dimen>
     <dimen name="qs_quick_tile_padding">12dp</dimen>
     <dimen name="qs_header_gear_translation">16dp</dimen>
     <dimen name="qs_header_tile_margin_horizontal">0dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 2270b60..c9c04d9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -17,6 +17,7 @@
 package com.android.systemui.qs;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
@@ -179,16 +180,56 @@
 
         protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
         private boolean mListening;
+        /** Size of the QS tile (width & height). */
+        private int mTileDimensionSize;
 
         public HeaderTileLayout(Context context) {
             super(context);
             setClipChildren(false);
             setClipToPadding(false);
-            setGravity(Gravity.CENTER_VERTICAL);
+
+            mTileDimensionSize = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.qs_quick_tile_size);
+
+            setGravity(Gravity.CENTER);
             setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
         }
 
         @Override
+        protected void onConfigurationChanged(Configuration newConfig) {
+            super.onConfigurationChanged(newConfig);
+
+            setGravity(Gravity.CENTER);
+            LayoutParams staticSpaceLayoutParams = generateSpaceLayoutParams(
+                    mContext.getResources().getDimensionPixelSize(
+                            R.dimen.qs_quick_tile_space_width));
+
+            // Update space params since they fill any open space in portrait orientation and have
+            // a static width in landscape orientation.
+            final int childViewCount = getChildCount();
+            for (int i = 0; i < childViewCount; i++) {
+                View childView = getChildAt(i);
+                if (childView instanceof Space) {
+                    childView.setLayoutParams(staticSpaceLayoutParams);
+                }
+            }
+        }
+
+        /**
+         * Returns {@link LayoutParams} based on the given {@code spaceWidth}. If the width is 0,
+         * then we're going to have the space expand to take up as much space as possible. If the
+         * width is non-zero, we want the inter-tile spacers to be fixed.
+         */
+        private LayoutParams generateSpaceLayoutParams(int spaceWidth) {
+            LayoutParams lp = new LayoutParams(spaceWidth, mTileDimensionSize);
+            if (spaceWidth == 0) {
+                lp.weight = 1;
+            }
+            lp.gravity = Gravity.CENTER;
+            return lp;
+        }
+
+        @Override
         public void setListening(boolean listening) {
             if (mListening == listening) return;
             mListening = listening;
@@ -200,25 +241,22 @@
         @Override
         public void addTile(TileRecord tile) {
             if (getChildCount() != 0) {
-                // Add a spacer.
-                addView(new Space(mContext), getChildCount(), generateSpaceParams());
+                // Add a spacer between tiles. We want static-width spaces if we're in landscape to
+                // keep the tiles close. For portrait, we stick with spaces that fill up any
+                // available space.
+                LayoutParams spaceLayoutParams = generateSpaceLayoutParams(
+                        mContext.getResources().getDimensionPixelSize(
+                                R.dimen.qs_quick_tile_space_width));
+                addView(new Space(mContext), getChildCount(), spaceLayoutParams);
             }
-            addView(tile.tileView, getChildCount(), generateLayoutParams());
+
+            addView(tile.tileView, getChildCount(), generateTileLayoutParams());
             mRecords.add(tile);
             tile.tile.setListening(this, mListening);
         }
 
-        private LayoutParams generateSpaceParams() {
-            int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
-            LayoutParams lp = new LayoutParams(0, size);
-            lp.weight = 1;
-            lp.gravity = Gravity.CENTER;
-            return lp;
-        }
-
-        private LayoutParams generateLayoutParams() {
-            int size = mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
-            LayoutParams lp = new LayoutParams(size, size);
+        private LayoutParams generateTileLayoutParams() {
+            LayoutParams lp = new LayoutParams(mTileDimensionSize, mTileDimensionSize);
             lp.gravity = Gravity.CENTER;
             return lp;
         }
@@ -237,8 +275,8 @@
         }
 
         private int getChildIndex(QSTileView tileView) {
-            final int N = getChildCount();
-            for (int i = 0; i < N; i++) {
+            final int childViewCount = getChildCount();
+            for (int i = 0; i < childViewCount; i++) {
                 if (getChildAt(i) == tileView) {
                     return i;
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index a39800d..58f8baa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -171,7 +171,7 @@
     private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
         @Override
         public void onConnectionChanged(boolean isConnected) {
-            mNavigationBarView.onOverviewProxyConnectionChanged(isConnected);
+            mNavigationBarView.updateStates();
             updateScreenPinningGestures();
             WindowManagerWrapper.getInstance()
                     .setNavBarVirtualKeyHapticFeedbackEnabled(!isConnected);
@@ -188,6 +188,7 @@
         @Override
         public void onInteractionFlagsChanged(@InteractionType int flags) {
             mNavigationBarView.updateStates();
+            updateScreenPinningGestures();
         }
     };
 
@@ -925,7 +926,9 @@
     private boolean onLongPressRecents() {
         if (mRecents == null || !ActivityManager.supportsMultiWindow(getContext())
                 || !mDivider.getView().getSnapAlgorithm().isSplitScreenFeasible()
-                || Recents.getConfiguration().isLowRamDevice) {
+                || Recents.getConfiguration().isLowRamDevice
+                // If we are connected to the overview service, then disable the recents button
+                || mOverviewProxyService.getProxy() != null) {
             return false;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 88bc6ea..b4cb088 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -681,6 +681,7 @@
         updateSlippery();
         reloadNavIcons();
         updateNavButtonIcons();
+        setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
     }
 
     private void updateSlippery() {
@@ -816,11 +817,6 @@
         }
     }
 
-    public void onOverviewProxyConnectionChanged(boolean isConnected) {
-        updateStates();
-        setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
-    }
-
     @Override
     protected void onDraw(Canvas canvas) {
         mGestureHelper.onDraw(canvas);
@@ -1045,7 +1041,7 @@
         onPluginDisconnected(null); // Create default gesture helper
         Dependency.get(PluginManager.class).addPluginListener(this,
                 NavGesture.class, false /* Only one */);
-        setUpSwipeUpOnboarding(mOverviewProxyService.getProxy() != null);
+        setUpSwipeUpOnboarding(isQuickStepSwipeUpEnabled());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
index 4313d17..711d40b 100644
--- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
+++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java
@@ -60,8 +60,14 @@
         int[] backlightRange = resources.getIntArray(
                 com.android.internal.R.array.config_screenBrightnessBacklight);
 
+        float[] minimumBrightnessCurveLux = getLuxLevels(resources.getIntArray(
+                com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveLux));
+        float[] minimumBrightnessCurveNits = getFloatArray(resources.obtainTypedArray(
+                com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveNits));
+
         if (isValidMapping(nitsRange, backlightRange)
-                && isValidMapping(luxLevels, brightnessLevelsNits)) {
+                && isValidMapping(luxLevels, brightnessLevelsNits)
+                && isValidMapping(minimumBrightnessCurveLux, minimumBrightnessCurveNits)) {
             int minimumBacklight = resources.getInteger(
                     com.android.internal.R.integer.config_screenBrightnessSettingMinimum);
             int maximumBacklight = resources.getInteger(
@@ -73,7 +79,8 @@
             }
             BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder();
             builder.setCurve(luxLevels, brightnessLevelsNits);
-            return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange);
+            return new PhysicalMappingStrategy(builder.build(), nitsRange, backlightRange,
+                    minimumBrightnessCurveLux, minimumBrightnessCurveNits);
         } else if (isValidMapping(luxLevels, brightnessLevelsBacklight)) {
             return new SimpleMappingStrategy(luxLevels, brightnessLevelsBacklight);
         } else {
@@ -448,8 +455,11 @@
         private float mUserLux;
         private float mUserBrightness;
 
+        private final Spline mMinimumBrightnessCurve;
+
         public PhysicalMappingStrategy(BrightnessConfiguration config,
-                float[] nits, int[] backlight) {
+                float[] nits, int[] backlight, float[] minimumBrightnessCurveLux,
+                float[] minimumBrightnessCurveNits) {
             Preconditions.checkArgument(nits.length != 0 && backlight.length != 0,
                     "Nits and backlight arrays must not be empty!");
             Preconditions.checkArgument(nits.length == backlight.length,
@@ -469,6 +479,9 @@
                 normalizedBacklight[i] = normalizeAbsoluteBrightness(backlight[i]);
             }
 
+            mMinimumBrightnessCurve = Spline.createSpline(
+                minimumBrightnessCurveLux, minimumBrightnessCurveNits);
+
             mNitsToBacklightSpline = createSpline(nits, normalizedBacklight);
             mBacklightToNitsSpline = createSpline(normalizedBacklight, nits);
 
@@ -484,7 +497,7 @@
             if (config.equals(mConfig)) {
                 return false;
             }
-
+            validateBrightnessConfiguration(config);
             Pair<float[], float[]> curve = config.getCurve();
             mBrightnessSpline = createSpline(curve.first /*lux*/, curve.second /*nits*/);
             mConfig = config;
@@ -549,5 +562,24 @@
             pw.println("  mUserLux=" + mUserLux);
             pw.println("  mUserBrightness=" + mUserBrightness);
         }
+
+        private void validateBrightnessConfiguration(BrightnessConfiguration config) {
+            Pair<float[], float[]> curve = config.getCurve();
+            Spline brightnessSpline = Spline.createSpline(curve.first, curve.second);
+            if (isBrightnessSplineTooDark(brightnessSpline)) {
+                throw new IllegalArgumentException("brightness curve is too dark");
+            }
+        }
+
+        private boolean isBrightnessSplineTooDark(Spline brightnessSpline) {
+            float[] lux = mDefaultConfig.getCurve().first;
+            for (int i = 0; i < lux.length; i++) {
+                if (brightnessSpline.interpolate(lux[i]) <
+                        mMinimumBrightnessCurve.interpolate(lux[i])) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 }
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 abe55bb..8365fd2 100644
--- a/services/core/java/com/android/server/job/controllers/ConnectivityController.java
+++ b/services/core/java/com/android/server/job/controllers/ConnectivityController.java
@@ -160,7 +160,7 @@
     private static boolean isRelaxedSatisfied(JobStatus jobStatus, Network network,
             NetworkCapabilities capabilities, Constants constants) {
         // Only consider doing this for prefetching jobs
-        if ((jobStatus.getJob().getFlags() & JobInfo.FLAG_IS_PREFETCH) == 0) {
+        if (!jobStatus.getJob().isPrefetch()) {
             return false;
         }
 
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
index 2714d5e..d793842 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistConfig.java
@@ -107,6 +107,10 @@
      * Reload watchlist by reading config file.
      */
     public void reloadConfig() {
+        if (!mXmlFile.exists()) {
+            // No config file
+            return;
+        }
         try (FileInputStream stream = new FileInputStream(mXmlFile)){
             final List<byte[]> crc32DomainList = new ArrayList<>();
             final List<byte[]> sha256DomainList = new ArrayList<>();
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
index f5ba889..e20a510 100644
--- a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
@@ -87,6 +87,10 @@
     }
 
     public void reloadSettings() {
+        if (!mXmlFile.exists()) {
+            // No settings config
+            return;
+        }
         try (FileInputStream stream = mXmlFile.openRead()){
             XmlPullParser parser = Xml.newPullParser();
             parser.setInput(stream, StandardCharsets.UTF_8.name());
@@ -97,7 +101,7 @@
                     mPrivacySecretKey = parseSecretKey(parser);
                 }
             }
-            Log.i(TAG, "Reload watchlist settings done");
+            Slog.i(TAG, "Reload watchlist settings done");
         } catch (IllegalStateException | NullPointerException | NumberFormatException |
                 XmlPullParserException | IOException | IndexOutOfBoundsException e) {
             Slog.e(TAG, "Failed parsing xml", e);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 19d6691..87a7a74 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -51,6 +51,7 @@
 import com.google.android.collect.Sets;
 
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import com.android.server.wm.utils.InsetUtils;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -400,9 +401,11 @@
             if (mainWindow == null) {
                 return null;
             }
+            final Rect insets = new Rect(mainWindow.mContentInsets);
+            InsetUtils.addInsets(insets, mainWindow.mAppToken.getLetterboxInsets());
             mTarget = new RemoteAnimationTarget(mTask.mTaskId, MODE_CLOSING, mCapturedLeash,
                     !mTask.fillsParent(), mainWindow.mWinAnimator.mLastClipRect,
-                    mainWindow.mContentInsets, mTask.getPrefixOrderIndex(), position, bounds,
+                    insets, mTask.getPrefixOrderIndex(), position, bounds,
                     mTask.getWindowConfiguration(), mIsRecentTaskInvisible);
             return mTarget;
         }
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index c590067..3e7feda 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -16,14 +16,15 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.AnimationAdapterProto.REMOTE;
+import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.AnimationAdapterProto.REMOTE;
-import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
 
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -37,6 +38,7 @@
 
 import com.android.internal.util.FastPrintWriter;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+import com.android.server.wm.utils.InsetUtils;
 
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -194,12 +196,17 @@
 
         @Override
         public void onAnimationFinished() throws RemoteException {
-            if (mOuter != null) {
-                mOuter.onAnimationFinished();
+            final long token = Binder.clearCallingIdentity();
+            try {
+                if (mOuter != null) {
+                    mOuter.onAnimationFinished();
 
-                // In case the client holds on to the finish callback, make sure we don't leak
-                // RemoteAnimationController which in turn would leak the runner on the client.
-                mOuter = null;
+                    // In case the client holds on to the finish callback, make sure we don't leak
+                    // RemoteAnimationController which in turn would leak the runner on the client.
+                    mOuter = null;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
         }
 
@@ -235,9 +242,11 @@
                     || mCapturedLeash == null) {
                 return null;
             }
+            final Rect insets = new Rect(mainWindow.mContentInsets);
+            InsetUtils.addInsets(insets, mAppWindowToken.getLetterboxInsets());
             mTarget = new RemoteAnimationTarget(task.mTaskId, getMode(),
                     mCapturedLeash, !mAppWindowToken.fillsParent(),
-                    mainWindow.mWinAnimator.mLastClipRect, mainWindow.mContentInsets,
+                    mainWindow.mWinAnimator.mLastClipRect, insets,
                     mAppWindowToken.getPrefixOrderIndex(), mPosition, mStackBounds,
                     task.getWindowConfiguration(), false /*isNotInRecents*/);
             return mTarget;
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 970a8d7..5f9d679 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -27,7 +27,6 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.graphics.Color;
 import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
 import android.os.Environment;
@@ -45,6 +44,7 @@
 import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
 import com.android.server.policy.WindowManagerPolicy.StartingSurface;
 import com.android.server.wm.TaskSnapshotSurface.SystemBarBackgroundPainter;
+import com.android.server.wm.utils.InsetUtils;
 
 import com.google.android.collect.Sets;
 
@@ -273,7 +273,7 @@
             return null;
         }
         return new TaskSnapshot(buffer, top.getConfiguration().orientation,
-                getInsetsFromTaskBounds(mainWindow, task),
+                getInsets(mainWindow),
                 isLowRamDevice /* reduced */, scaleFraction /* scale */,
                 true /* isRealSnapshot */);
     }
@@ -282,11 +282,11 @@
         return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT;
     }
 
-    private Rect getInsetsFromTaskBounds(WindowState state, Task task) {
+    private Rect getInsets(WindowState state) {
         // XXX(b/72757033): These are insets relative to the window frame, but we're really
         // interested in the insets relative to the task bounds.
-        Rect insets = minRect(state.mContentInsets, state.mStableInsets);
-        insets = maxRect(insets, state.mAppToken.getLetterboxInsets());
+        final Rect insets = minRect(state.mContentInsets, state.mStableInsets);
+        InsetUtils.addInsets(insets, state.mAppToken.getLetterboxInsets());
         return insets;
     }
 
@@ -297,13 +297,6 @@
                 Math.min(rect1.bottom, rect2.bottom));
     }
 
-    private Rect maxRect(Rect rect1, Rect rect2) {
-        return new Rect(Math.max(rect1.left, rect2.left),
-                Math.max(rect1.top, rect2.top),
-                Math.max(rect1.right, rect2.right),
-                Math.max(rect1.bottom, rect2.bottom));
-    }
-
     /**
      * Retrieves all closing tasks based on the list of closing apps during an app transition.
      */
diff --git a/services/core/java/com/android/server/wm/utils/InsetUtils.java b/services/core/java/com/android/server/wm/utils/InsetUtils.java
new file mode 100644
index 0000000..b4a998a
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/InsetUtils.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm.utils;
+
+import android.graphics.Rect;
+
+/**
+ * Utility methods to handle insets represented as rects.
+ */
+public class InsetUtils {
+
+    private InsetUtils() {
+    }
+
+    /**
+     * Adds {@code insetsToAdd} to {@code inOutInsets}.
+     */
+    public static void addInsets(Rect inOutInsets, Rect insetsToAdd) {
+        inOutInsets.left += insetsToAdd.left;
+        inOutInsets.top += insetsToAdd.top;
+        inOutInsets.right += insetsToAdd.right;
+        inOutInsets.bottom += insetsToAdd.bottom;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
index fb25cf3..d922df3 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessMappingStrategyTest.java
@@ -85,6 +85,9 @@
         255
     };
 
+    private static final int[] MINIMUM_BRIGHTNESS_CURVE_LUX = { 2000, 4000 };
+    private static final float[] MINIMUM_BRIGHTNESS_CURVE_NITS = { 1.0f, 50.0f, 90.0f };
+
     private static final float[] DISPLAY_RANGE_NITS = { 2.685f, 478.5f };
     private static final int[] BACKLIGHT_RANGE = { 1, 255 };
 
@@ -381,6 +384,19 @@
                 com.android.internal.R.array.config_autoBrightnessDisplayValuesNits))
                 .thenReturn(mockBrightnessLevelNits);
 
+        int[] mockMinimumBrightnessCurveLux = new int[MINIMUM_BRIGHTNESS_CURVE_LUX.length];
+        for (int i = 0; i < mockMinimumBrightnessCurveLux.length; i++) {
+            mockMinimumBrightnessCurveLux[i] = (int) MINIMUM_BRIGHTNESS_CURVE_LUX[i];
+        }
+        when(mockResources.getIntArray(
+                com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveLux))
+                .thenReturn(mockMinimumBrightnessCurveLux);
+        TypedArray mockMinimumBrightnessCurveNits = createFloatTypedArray(
+                MINIMUM_BRIGHTNESS_CURVE_NITS);
+        when(mockResources.obtainTypedArray(
+                com.android.internal.R.array.config_autoBrightnessMinimumBrightnessCurveNits))
+                .thenReturn(mockMinimumBrightnessCurveNits);
+
         TypedArray mockNitsRange = createFloatTypedArray(nitsRange);
         when(mockResources.obtainTypedArray(
                 com.android.internal.R.array.config_screenBrightnessNits))
@@ -419,4 +435,78 @@
         return mockArray;
     }
 
+    private float[] getNearMinimumNits(float epsilon) {
+        float[] lux = new float[MINIMUM_BRIGHTNESS_CURVE_LUX.length + 1];
+        for (int i = 0; i < MINIMUM_BRIGHTNESS_CURVE_LUX.length; i++) {
+            lux[i+1] = MINIMUM_BRIGHTNESS_CURVE_LUX[i];
+        }
+        Spline minimumBrightnessCurve = Spline.createSpline(lux, MINIMUM_BRIGHTNESS_CURVE_NITS);
+        float[] nits = new float[LUX_LEVELS.length];
+        for (int i = 0; i < nits.length; i++) {
+            nits[i] = minimumBrightnessCurve.interpolate(LUX_LEVELS[i]) + epsilon;
+        }
+        return nits;
+    }
+
+    @Test
+    public void testCreateWithTooDarkBrightnessConfigurationThrowsException() {
+        float[] nits = getNearMinimumNits(-0.1f);
+        Resources res = createResources(LUX_LEVELS, nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+        Exception thrown = null;
+        try {
+            BrightnessMappingStrategy.create(res);
+        } catch (IllegalArgumentException e) {
+            thrown = e;
+        }
+        assertNotNull("Failed to throw IllegalArgumentException", thrown);
+    }
+
+    @Test
+    public void testCreationWithBrightEnoughBrightnessConfigurationDoesNotThrowException() {
+        float[] nits = getNearMinimumNits(0);
+        Resources res = createResources(LUX_LEVELS, nits, DISPLAY_RANGE_NITS, BACKLIGHT_RANGE);
+        assertNotNull("Failed to create BrightnessMappingStrategy",
+                BrightnessMappingStrategy.create(res));
+    }
+
+    @Test
+    public void testSettingTooDarkBrightnessConfigurationThrowsException() {
+        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS,
+                BACKLIGHT_RANGE);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+        assertNotNull("Failed to create BrightnessMappingStrategy", strategy);
+        float[] lux = new float[LUX_LEVELS.length];
+        for (int i = 0; i < lux.length; i++) {
+            lux[i] = LUX_LEVELS[i];
+        }
+        float[] nits = getNearMinimumNits(-0.1f);
+        BrightnessConfiguration config = new BrightnessConfiguration.Builder()
+                .setCurve(lux, nits)
+                .build();
+        Exception thrown = null;
+        try {
+            strategy.setBrightnessConfiguration(config);
+        } catch (IllegalArgumentException e) {
+            thrown = e;
+        }
+        assertNotNull("Failed to throw IllegalArgumentException", thrown);
+    }
+
+    @Test
+    public void testSettingBrightEnouhgBrightnessConfigurationDoesNotThrowException() {
+        Resources res = createResources(LUX_LEVELS, DISPLAY_LEVELS_NITS, DISPLAY_RANGE_NITS,
+                BACKLIGHT_RANGE);
+        BrightnessMappingStrategy strategy = BrightnessMappingStrategy.create(res);
+        assertNotNull("Failed to create BrightnessMappingStrategy", strategy);
+        float[] lux = new float[LUX_LEVELS.length];
+        for (int i = 0; i < lux.length; i++) {
+            lux[i] = LUX_LEVELS[i];
+        }
+        float[] nits = getNearMinimumNits(0);
+        BrightnessConfiguration config = new BrightnessConfiguration.Builder()
+                .setCurve(lux, nits)
+                .build();
+        assertTrue("failed to set brightness configuration",
+            strategy.setBrightnessConfiguration(config));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
index ead817a..c772956 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverySnapshotStorageTest.java
@@ -7,23 +7,19 @@
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
+import com.android.server.locksettings.recoverablekeystore.TestData;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.security.cert.CertificateException;
 import java.util.ArrayList;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class RecoverySnapshotStorageTest {
-    private static final KeyChainSnapshot MINIMAL_KEYCHAIN_SNAPSHOT = new KeyChainSnapshot.Builder()
-            .setCounterId(1)
-            .setSnapshotVersion(1)
-            .setServerParams(new byte[0])
-            .setMaxAttempts(10)
-            .setEncryptedRecoveryKeyBlob(new byte[0])
-            .setKeyChainProtectionParams(new ArrayList<>())
-            .setWrappedApplicationKeys(new ArrayList<>())
-            .build();
+    private static final KeyChainSnapshot MINIMAL_KEYCHAIN_SNAPSHOT =
+            createMinimalKeyChainSnapshot();
 
     private final RecoverySnapshotStorage mRecoverySnapshotStorage = new RecoverySnapshotStorage();
 
@@ -50,4 +46,21 @@
 
         assertNull(mRecoverySnapshotStorage.get(1000));
     }
+
+    private static KeyChainSnapshot createMinimalKeyChainSnapshot() {
+        try {
+            return new KeyChainSnapshot.Builder()
+                    .setCounterId(1)
+                    .setSnapshotVersion(1)
+                    .setServerParams(new byte[0])
+                    .setMaxAttempts(10)
+                    .setEncryptedRecoveryKeyBlob(new byte[0])
+                    .setKeyChainProtectionParams(new ArrayList<>())
+                    .setWrappedApplicationKeys(new ArrayList<>())
+                    .setTrustedHardwareCertPath(TestData.CERT_PATH_1)
+                    .build();
+        } catch (CertificateException e) {
+            throw new RuntimeException(e);
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java
new file mode 100644
index 0000000..d0f0fe3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.wm.utils;
+
+import static junit.framework.Assert.assertEquals;
+
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Pair;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class InsetUtilsTest {
+
+    @Test
+    public void testAdd() throws Exception {
+        final Rect rect1 = new Rect(10, 20, 30, 40);
+        final Rect rect2 = new Rect(50, 60, 70, 80);
+        InsetUtils.addInsets(rect1, rect2);
+        assertEquals(new Rect(60, 80, 100, 120), rect1);
+    }
+}
+