Merge "Reduced the retry after disconnect delay"
diff --git a/api/current.txt b/api/current.txt
index 739e7f2..b232abb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16686,6 +16686,7 @@
     field public static final java.lang.String ABBR_UTC_TZ = "ZZZZ";
     field public static final java.lang.String ABBR_WEEKDAY = "E";
     field public static final int AM_PM_FIELD = 14; // 0xe
+    field public static final int AM_PM_MIDNIGHT_NOON_FIELD = 35; // 0x23
     field public static final int DATE_FIELD = 3; // 0x3
     field public static final java.lang.String DAY = "d";
     field public static final int DAY_OF_WEEK_FIELD = 9; // 0x9
@@ -16695,6 +16696,7 @@
     field public static final int DOW_LOCAL_FIELD = 19; // 0x13
     field public static final int ERA_FIELD = 0; // 0x0
     field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
+    field public static final int FLEXIBLE_DAY_PERIOD_FIELD = 36; // 0x24
     field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
     field public static final int FULL = 0; // 0x0
     field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -16783,6 +16785,7 @@
     method public int getCalendarField();
     method public static android.icu.text.DateFormat.Field ofCalendarField(int);
     field public static final android.icu.text.DateFormat.Field AM_PM;
+    field public static final android.icu.text.DateFormat.Field AM_PM_MIDNIGHT_NOON;
     field public static final android.icu.text.DateFormat.Field DAY_OF_MONTH;
     field public static final android.icu.text.DateFormat.Field DAY_OF_WEEK;
     field public static final android.icu.text.DateFormat.Field DAY_OF_WEEK_IN_MONTH;
@@ -16790,6 +16793,7 @@
     field public static final android.icu.text.DateFormat.Field DOW_LOCAL;
     field public static final android.icu.text.DateFormat.Field ERA;
     field public static final android.icu.text.DateFormat.Field EXTENDED_YEAR;
+    field public static final android.icu.text.DateFormat.Field FLEXIBLE_DAY_PERIOD;
     field public static final android.icu.text.DateFormat.Field HOUR0;
     field public static final android.icu.text.DateFormat.Field HOUR1;
     field public static final android.icu.text.DateFormat.Field HOUR_OF_DAY0;
@@ -16961,70 +16965,70 @@
     ctor public DecimalFormat(java.lang.String);
     ctor public DecimalFormat(java.lang.String, android.icu.text.DecimalFormatSymbols);
     ctor public DecimalFormat(java.lang.String, android.icu.text.DecimalFormatSymbols, android.icu.text.CurrencyPluralInfo, int);
-    method public void applyLocalizedPattern(java.lang.String);
-    method public void applyPattern(java.lang.String);
-    method public boolean areSignificantDigitsUsed();
+    method public synchronized void applyLocalizedPattern(java.lang.String);
+    method public synchronized void applyPattern(java.lang.String);
+    method public synchronized boolean areSignificantDigitsUsed();
     method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
-    method public android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
-    method public android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
-    method public android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
-    method public int getFormatWidth();
-    method public int getGroupingSize();
-    method public java.math.MathContext getMathContext();
-    method public android.icu.math.MathContext getMathContextICU();
-    method public int getMaximumSignificantDigits();
-    method public byte getMinimumExponentDigits();
-    method public int getMinimumSignificantDigits();
-    method public int getMultiplier();
-    method public java.lang.String getNegativePrefix();
-    method public java.lang.String getNegativeSuffix();
-    method public char getPadCharacter();
-    method public int getPadPosition();
-    method public int getParseMaxDigits();
-    method public java.lang.String getPositivePrefix();
-    method public java.lang.String getPositiveSuffix();
-    method public java.math.BigDecimal getRoundingIncrement();
-    method public int getSecondaryGroupingSize();
-    method public boolean isDecimalPatternMatchRequired();
-    method public boolean isDecimalSeparatorAlwaysShown();
-    method public boolean isExponentSignAlwaysShown();
-    method public boolean isParseBigDecimal();
-    method public boolean isScientificNotation();
+    method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
+    method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
+    method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
+    method public synchronized int getFormatWidth();
+    method public synchronized int getGroupingSize();
+    method public synchronized java.math.MathContext getMathContext();
+    method public synchronized android.icu.math.MathContext getMathContextICU();
+    method public synchronized int getMaximumSignificantDigits();
+    method public synchronized byte getMinimumExponentDigits();
+    method public synchronized int getMinimumSignificantDigits();
+    method public synchronized int getMultiplier();
+    method public synchronized java.lang.String getNegativePrefix();
+    method public synchronized java.lang.String getNegativeSuffix();
+    method public synchronized char getPadCharacter();
+    method public synchronized int getPadPosition();
+    method public deprecated int getParseMaxDigits();
+    method public synchronized java.lang.String getPositivePrefix();
+    method public synchronized java.lang.String getPositiveSuffix();
+    method public synchronized java.math.BigDecimal getRoundingIncrement();
+    method public synchronized int getSecondaryGroupingSize();
+    method public synchronized boolean isDecimalPatternMatchRequired();
+    method public synchronized boolean isDecimalSeparatorAlwaysShown();
+    method public synchronized boolean isExponentSignAlwaysShown();
+    method public synchronized boolean isParseBigDecimal();
+    method public synchronized boolean isScientificNotation();
     method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
-    method public void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
-    method public void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
-    method public void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
-    method public void setDecimalPatternMatchRequired(boolean);
-    method public void setDecimalSeparatorAlwaysShown(boolean);
-    method public void setExponentSignAlwaysShown(boolean);
-    method public void setFormatWidth(int);
-    method public void setGroupingSize(int);
-    method public void setMathContext(java.math.MathContext);
-    method public void setMathContextICU(android.icu.math.MathContext);
-    method public void setMaximumSignificantDigits(int);
-    method public void setMinimumExponentDigits(byte);
-    method public void setMinimumSignificantDigits(int);
-    method public void setMultiplier(int);
-    method public void setNegativePrefix(java.lang.String);
-    method public void setNegativeSuffix(java.lang.String);
-    method public void setPadCharacter(char);
-    method public void setPadPosition(int);
-    method public void setParseBigDecimal(boolean);
-    method public void setParseMaxDigits(int);
-    method public void setPositivePrefix(java.lang.String);
-    method public void setPositiveSuffix(java.lang.String);
-    method public void setRoundingIncrement(java.math.BigDecimal);
-    method public void setRoundingIncrement(android.icu.math.BigDecimal);
-    method public void setRoundingIncrement(double);
-    method public void setScientificNotation(boolean);
-    method public void setSecondaryGroupingSize(int);
-    method public void setSignificantDigitsUsed(boolean);
-    method public java.lang.String toLocalizedPattern();
-    method public java.lang.String toPattern();
+    method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
+    method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
+    method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
+    method public synchronized void setDecimalPatternMatchRequired(boolean);
+    method public synchronized void setDecimalSeparatorAlwaysShown(boolean);
+    method public synchronized void setExponentSignAlwaysShown(boolean);
+    method public synchronized void setFormatWidth(int);
+    method public synchronized void setGroupingSize(int);
+    method public synchronized void setMathContext(java.math.MathContext);
+    method public synchronized void setMathContextICU(android.icu.math.MathContext);
+    method public synchronized void setMaximumSignificantDigits(int);
+    method public synchronized void setMinimumExponentDigits(byte);
+    method public synchronized void setMinimumSignificantDigits(int);
+    method public synchronized void setMultiplier(int);
+    method public synchronized void setNegativePrefix(java.lang.String);
+    method public synchronized void setNegativeSuffix(java.lang.String);
+    method public synchronized void setPadCharacter(char);
+    method public synchronized void setPadPosition(int);
+    method public synchronized void setParseBigDecimal(boolean);
+    method public deprecated void setParseMaxDigits(int);
+    method public synchronized void setPositivePrefix(java.lang.String);
+    method public synchronized void setPositiveSuffix(java.lang.String);
+    method public synchronized void setRoundingIncrement(java.math.BigDecimal);
+    method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
+    method public synchronized void setRoundingIncrement(double);
+    method public synchronized void setScientificNotation(boolean);
+    method public synchronized void setSecondaryGroupingSize(int);
+    method public synchronized void setSignificantDigitsUsed(boolean);
+    method public synchronized java.lang.String toLocalizedPattern();
+    method public synchronized java.lang.String toPattern();
     field public static final int PAD_AFTER_PREFIX = 1; // 0x1
     field public static final int PAD_AFTER_SUFFIX = 3; // 0x3
     field public static final int PAD_BEFORE_PREFIX = 0; // 0x0
@@ -17572,6 +17576,8 @@
     method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
     method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
     method public java.lang.String format(android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit);
+    method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit);
+    method public java.lang.String formatNumeric(double, android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit);
     method public android.icu.text.DisplayContext getCapitalizationContext();
     method public android.icu.text.RelativeDateTimeFormatter.Style getFormatStyle();
     method public static android.icu.text.RelativeDateTimeFormatter getInstance();
@@ -17611,6 +17617,26 @@
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.Direction THIS;
   }
 
+  public static final class RelativeDateTimeFormatter.RelativeDateTimeUnit extends java.lang.Enum {
+    method public static android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit valueOf(java.lang.String);
+    method public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit[] values();
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit DAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit FRIDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit HOUR;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit MINUTE;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit MONDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit MONTH;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit QUARTER;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit SATURDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit SECOND;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit SUNDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit THURSDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit TUESDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit WEDNESDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit WEEK;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit YEAR;
+  }
+
   public static final class RelativeDateTimeFormatter.RelativeUnit extends java.lang.Enum {
     method public static android.icu.text.RelativeDateTimeFormatter.RelativeUnit valueOf(java.lang.String);
     method public static final android.icu.text.RelativeDateTimeFormatter.RelativeUnit[] values();
@@ -18681,6 +18707,7 @@
     field public static final android.icu.util.MeasureUnit FOOT;
     field public static final android.icu.util.MeasureUnit FURLONG;
     field public static final android.icu.util.MeasureUnit GALLON;
+    field public static final android.icu.util.MeasureUnit GALLON_IMPERIAL;
     field public static final android.icu.util.MeasureUnit GENERIC_TEMPERATURE;
     field public static final android.icu.util.MeasureUnit GIGABIT;
     field public static final android.icu.util.MeasureUnit GIGABYTE;
@@ -18729,11 +18756,13 @@
     field public static final android.icu.util.MeasureUnit MICROSECOND;
     field public static final android.icu.util.MeasureUnit MILE;
     field public static final android.icu.util.MeasureUnit MILE_PER_GALLON;
+    field public static final android.icu.util.MeasureUnit MILE_PER_GALLON_IMPERIAL;
     field public static final android.icu.util.MeasureUnit MILE_PER_HOUR;
     field public static final android.icu.util.MeasureUnit MILE_SCANDINAVIAN;
     field public static final android.icu.util.MeasureUnit MILLIAMPERE;
     field public static final android.icu.util.MeasureUnit MILLIBAR;
     field public static final android.icu.util.MeasureUnit MILLIGRAM;
+    field public static final android.icu.util.MeasureUnit MILLIGRAM_PER_DECILITER;
     field public static final android.icu.util.MeasureUnit MILLILITER;
     field public static final android.icu.util.MeasureUnit MILLIMETER;
     field public static final android.icu.util.MeasureUnit MILLIMETER_OF_MERCURY;
@@ -19037,7 +19066,7 @@
     field public static final int JAVA_TIME = 0; // 0x0
     field public static final int MAC_OLD_TIME = 5; // 0x5
     field public static final int MAC_TIME = 6; // 0x6
-    field public static final int MAX_SCALE = 10; // 0xa
+    field public static final deprecated int MAX_SCALE = 10; // 0xa
     field public static final int TO_MAX_VALUE = 5; // 0x5
     field public static final int TO_MIN_VALUE = 4; // 0x4
     field public static final int UNITS_VALUE = 0; // 0x0
diff --git a/api/system-current.txt b/api/system-current.txt
index 0aa5d58..10b0221 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -17901,6 +17901,7 @@
     field public static final java.lang.String ABBR_UTC_TZ = "ZZZZ";
     field public static final java.lang.String ABBR_WEEKDAY = "E";
     field public static final int AM_PM_FIELD = 14; // 0xe
+    field public static final int AM_PM_MIDNIGHT_NOON_FIELD = 35; // 0x23
     field public static final int DATE_FIELD = 3; // 0x3
     field public static final java.lang.String DAY = "d";
     field public static final int DAY_OF_WEEK_FIELD = 9; // 0x9
@@ -17910,6 +17911,7 @@
     field public static final int DOW_LOCAL_FIELD = 19; // 0x13
     field public static final int ERA_FIELD = 0; // 0x0
     field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
+    field public static final int FLEXIBLE_DAY_PERIOD_FIELD = 36; // 0x24
     field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
     field public static final int FULL = 0; // 0x0
     field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -17998,6 +18000,7 @@
     method public int getCalendarField();
     method public static android.icu.text.DateFormat.Field ofCalendarField(int);
     field public static final android.icu.text.DateFormat.Field AM_PM;
+    field public static final android.icu.text.DateFormat.Field AM_PM_MIDNIGHT_NOON;
     field public static final android.icu.text.DateFormat.Field DAY_OF_MONTH;
     field public static final android.icu.text.DateFormat.Field DAY_OF_WEEK;
     field public static final android.icu.text.DateFormat.Field DAY_OF_WEEK_IN_MONTH;
@@ -18005,6 +18008,7 @@
     field public static final android.icu.text.DateFormat.Field DOW_LOCAL;
     field public static final android.icu.text.DateFormat.Field ERA;
     field public static final android.icu.text.DateFormat.Field EXTENDED_YEAR;
+    field public static final android.icu.text.DateFormat.Field FLEXIBLE_DAY_PERIOD;
     field public static final android.icu.text.DateFormat.Field HOUR0;
     field public static final android.icu.text.DateFormat.Field HOUR1;
     field public static final android.icu.text.DateFormat.Field HOUR_OF_DAY0;
@@ -18176,70 +18180,70 @@
     ctor public DecimalFormat(java.lang.String);
     ctor public DecimalFormat(java.lang.String, android.icu.text.DecimalFormatSymbols);
     ctor public DecimalFormat(java.lang.String, android.icu.text.DecimalFormatSymbols, android.icu.text.CurrencyPluralInfo, int);
-    method public void applyLocalizedPattern(java.lang.String);
-    method public void applyPattern(java.lang.String);
-    method public boolean areSignificantDigitsUsed();
+    method public synchronized void applyLocalizedPattern(java.lang.String);
+    method public synchronized void applyPattern(java.lang.String);
+    method public synchronized boolean areSignificantDigitsUsed();
     method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
-    method public android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
-    method public android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
-    method public android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
-    method public int getFormatWidth();
-    method public int getGroupingSize();
-    method public java.math.MathContext getMathContext();
-    method public android.icu.math.MathContext getMathContextICU();
-    method public int getMaximumSignificantDigits();
-    method public byte getMinimumExponentDigits();
-    method public int getMinimumSignificantDigits();
-    method public int getMultiplier();
-    method public java.lang.String getNegativePrefix();
-    method public java.lang.String getNegativeSuffix();
-    method public char getPadCharacter();
-    method public int getPadPosition();
-    method public int getParseMaxDigits();
-    method public java.lang.String getPositivePrefix();
-    method public java.lang.String getPositiveSuffix();
-    method public java.math.BigDecimal getRoundingIncrement();
-    method public int getSecondaryGroupingSize();
-    method public boolean isDecimalPatternMatchRequired();
-    method public boolean isDecimalSeparatorAlwaysShown();
-    method public boolean isExponentSignAlwaysShown();
-    method public boolean isParseBigDecimal();
-    method public boolean isScientificNotation();
+    method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
+    method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
+    method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
+    method public synchronized int getFormatWidth();
+    method public synchronized int getGroupingSize();
+    method public synchronized java.math.MathContext getMathContext();
+    method public synchronized android.icu.math.MathContext getMathContextICU();
+    method public synchronized int getMaximumSignificantDigits();
+    method public synchronized byte getMinimumExponentDigits();
+    method public synchronized int getMinimumSignificantDigits();
+    method public synchronized int getMultiplier();
+    method public synchronized java.lang.String getNegativePrefix();
+    method public synchronized java.lang.String getNegativeSuffix();
+    method public synchronized char getPadCharacter();
+    method public synchronized int getPadPosition();
+    method public deprecated int getParseMaxDigits();
+    method public synchronized java.lang.String getPositivePrefix();
+    method public synchronized java.lang.String getPositiveSuffix();
+    method public synchronized java.math.BigDecimal getRoundingIncrement();
+    method public synchronized int getSecondaryGroupingSize();
+    method public synchronized boolean isDecimalPatternMatchRequired();
+    method public synchronized boolean isDecimalSeparatorAlwaysShown();
+    method public synchronized boolean isExponentSignAlwaysShown();
+    method public synchronized boolean isParseBigDecimal();
+    method public synchronized boolean isScientificNotation();
     method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
-    method public void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
-    method public void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
-    method public void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
-    method public void setDecimalPatternMatchRequired(boolean);
-    method public void setDecimalSeparatorAlwaysShown(boolean);
-    method public void setExponentSignAlwaysShown(boolean);
-    method public void setFormatWidth(int);
-    method public void setGroupingSize(int);
-    method public void setMathContext(java.math.MathContext);
-    method public void setMathContextICU(android.icu.math.MathContext);
-    method public void setMaximumSignificantDigits(int);
-    method public void setMinimumExponentDigits(byte);
-    method public void setMinimumSignificantDigits(int);
-    method public void setMultiplier(int);
-    method public void setNegativePrefix(java.lang.String);
-    method public void setNegativeSuffix(java.lang.String);
-    method public void setPadCharacter(char);
-    method public void setPadPosition(int);
-    method public void setParseBigDecimal(boolean);
-    method public void setParseMaxDigits(int);
-    method public void setPositivePrefix(java.lang.String);
-    method public void setPositiveSuffix(java.lang.String);
-    method public void setRoundingIncrement(java.math.BigDecimal);
-    method public void setRoundingIncrement(android.icu.math.BigDecimal);
-    method public void setRoundingIncrement(double);
-    method public void setScientificNotation(boolean);
-    method public void setSecondaryGroupingSize(int);
-    method public void setSignificantDigitsUsed(boolean);
-    method public java.lang.String toLocalizedPattern();
-    method public java.lang.String toPattern();
+    method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
+    method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
+    method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
+    method public synchronized void setDecimalPatternMatchRequired(boolean);
+    method public synchronized void setDecimalSeparatorAlwaysShown(boolean);
+    method public synchronized void setExponentSignAlwaysShown(boolean);
+    method public synchronized void setFormatWidth(int);
+    method public synchronized void setGroupingSize(int);
+    method public synchronized void setMathContext(java.math.MathContext);
+    method public synchronized void setMathContextICU(android.icu.math.MathContext);
+    method public synchronized void setMaximumSignificantDigits(int);
+    method public synchronized void setMinimumExponentDigits(byte);
+    method public synchronized void setMinimumSignificantDigits(int);
+    method public synchronized void setMultiplier(int);
+    method public synchronized void setNegativePrefix(java.lang.String);
+    method public synchronized void setNegativeSuffix(java.lang.String);
+    method public synchronized void setPadCharacter(char);
+    method public synchronized void setPadPosition(int);
+    method public synchronized void setParseBigDecimal(boolean);
+    method public deprecated void setParseMaxDigits(int);
+    method public synchronized void setPositivePrefix(java.lang.String);
+    method public synchronized void setPositiveSuffix(java.lang.String);
+    method public synchronized void setRoundingIncrement(java.math.BigDecimal);
+    method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
+    method public synchronized void setRoundingIncrement(double);
+    method public synchronized void setScientificNotation(boolean);
+    method public synchronized void setSecondaryGroupingSize(int);
+    method public synchronized void setSignificantDigitsUsed(boolean);
+    method public synchronized java.lang.String toLocalizedPattern();
+    method public synchronized java.lang.String toPattern();
     field public static final int PAD_AFTER_PREFIX = 1; // 0x1
     field public static final int PAD_AFTER_SUFFIX = 3; // 0x3
     field public static final int PAD_BEFORE_PREFIX = 0; // 0x0
@@ -18787,6 +18791,8 @@
     method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
     method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
     method public java.lang.String format(android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit);
+    method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit);
+    method public java.lang.String formatNumeric(double, android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit);
     method public android.icu.text.DisplayContext getCapitalizationContext();
     method public android.icu.text.RelativeDateTimeFormatter.Style getFormatStyle();
     method public static android.icu.text.RelativeDateTimeFormatter getInstance();
@@ -18826,6 +18832,26 @@
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.Direction THIS;
   }
 
+  public static final class RelativeDateTimeFormatter.RelativeDateTimeUnit extends java.lang.Enum {
+    method public static android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit valueOf(java.lang.String);
+    method public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit[] values();
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit DAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit FRIDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit HOUR;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit MINUTE;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit MONDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit MONTH;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit QUARTER;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit SATURDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit SECOND;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit SUNDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit THURSDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit TUESDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit WEDNESDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit WEEK;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit YEAR;
+  }
+
   public static final class RelativeDateTimeFormatter.RelativeUnit extends java.lang.Enum {
     method public static android.icu.text.RelativeDateTimeFormatter.RelativeUnit valueOf(java.lang.String);
     method public static final android.icu.text.RelativeDateTimeFormatter.RelativeUnit[] values();
@@ -19896,6 +19922,7 @@
     field public static final android.icu.util.MeasureUnit FOOT;
     field public static final android.icu.util.MeasureUnit FURLONG;
     field public static final android.icu.util.MeasureUnit GALLON;
+    field public static final android.icu.util.MeasureUnit GALLON_IMPERIAL;
     field public static final android.icu.util.MeasureUnit GENERIC_TEMPERATURE;
     field public static final android.icu.util.MeasureUnit GIGABIT;
     field public static final android.icu.util.MeasureUnit GIGABYTE;
@@ -19944,11 +19971,13 @@
     field public static final android.icu.util.MeasureUnit MICROSECOND;
     field public static final android.icu.util.MeasureUnit MILE;
     field public static final android.icu.util.MeasureUnit MILE_PER_GALLON;
+    field public static final android.icu.util.MeasureUnit MILE_PER_GALLON_IMPERIAL;
     field public static final android.icu.util.MeasureUnit MILE_PER_HOUR;
     field public static final android.icu.util.MeasureUnit MILE_SCANDINAVIAN;
     field public static final android.icu.util.MeasureUnit MILLIAMPERE;
     field public static final android.icu.util.MeasureUnit MILLIBAR;
     field public static final android.icu.util.MeasureUnit MILLIGRAM;
+    field public static final android.icu.util.MeasureUnit MILLIGRAM_PER_DECILITER;
     field public static final android.icu.util.MeasureUnit MILLILITER;
     field public static final android.icu.util.MeasureUnit MILLIMETER;
     field public static final android.icu.util.MeasureUnit MILLIMETER_OF_MERCURY;
@@ -20252,7 +20281,7 @@
     field public static final int JAVA_TIME = 0; // 0x0
     field public static final int MAC_OLD_TIME = 5; // 0x5
     field public static final int MAC_TIME = 6; // 0x6
-    field public static final int MAX_SCALE = 10; // 0xa
+    field public static final deprecated int MAX_SCALE = 10; // 0xa
     field public static final int TO_MAX_VALUE = 5; // 0x5
     field public static final int TO_MIN_VALUE = 4; // 0x4
     field public static final int UNITS_VALUE = 0; // 0x0
diff --git a/api/test-current.txt b/api/test-current.txt
index 93c9768..15598db 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -16704,6 +16704,7 @@
     field public static final java.lang.String ABBR_UTC_TZ = "ZZZZ";
     field public static final java.lang.String ABBR_WEEKDAY = "E";
     field public static final int AM_PM_FIELD = 14; // 0xe
+    field public static final int AM_PM_MIDNIGHT_NOON_FIELD = 35; // 0x23
     field public static final int DATE_FIELD = 3; // 0x3
     field public static final java.lang.String DAY = "d";
     field public static final int DAY_OF_WEEK_FIELD = 9; // 0x9
@@ -16713,6 +16714,7 @@
     field public static final int DOW_LOCAL_FIELD = 19; // 0x13
     field public static final int ERA_FIELD = 0; // 0x0
     field public static final int EXTENDED_YEAR_FIELD = 20; // 0x14
+    field public static final int FLEXIBLE_DAY_PERIOD_FIELD = 36; // 0x24
     field public static final int FRACTIONAL_SECOND_FIELD = 8; // 0x8
     field public static final int FULL = 0; // 0x0
     field public static final java.lang.String GENERIC_TZ = "vvvv";
@@ -16801,6 +16803,7 @@
     method public int getCalendarField();
     method public static android.icu.text.DateFormat.Field ofCalendarField(int);
     field public static final android.icu.text.DateFormat.Field AM_PM;
+    field public static final android.icu.text.DateFormat.Field AM_PM_MIDNIGHT_NOON;
     field public static final android.icu.text.DateFormat.Field DAY_OF_MONTH;
     field public static final android.icu.text.DateFormat.Field DAY_OF_WEEK;
     field public static final android.icu.text.DateFormat.Field DAY_OF_WEEK_IN_MONTH;
@@ -16808,6 +16811,7 @@
     field public static final android.icu.text.DateFormat.Field DOW_LOCAL;
     field public static final android.icu.text.DateFormat.Field ERA;
     field public static final android.icu.text.DateFormat.Field EXTENDED_YEAR;
+    field public static final android.icu.text.DateFormat.Field FLEXIBLE_DAY_PERIOD;
     field public static final android.icu.text.DateFormat.Field HOUR0;
     field public static final android.icu.text.DateFormat.Field HOUR1;
     field public static final android.icu.text.DateFormat.Field HOUR_OF_DAY0;
@@ -16979,70 +16983,70 @@
     ctor public DecimalFormat(java.lang.String);
     ctor public DecimalFormat(java.lang.String, android.icu.text.DecimalFormatSymbols);
     ctor public DecimalFormat(java.lang.String, android.icu.text.DecimalFormatSymbols, android.icu.text.CurrencyPluralInfo, int);
-    method public void applyLocalizedPattern(java.lang.String);
-    method public void applyPattern(java.lang.String);
-    method public boolean areSignificantDigitsUsed();
+    method public synchronized void applyLocalizedPattern(java.lang.String);
+    method public synchronized void applyPattern(java.lang.String);
+    method public synchronized boolean areSignificantDigitsUsed();
     method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
     method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
-    method public android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
-    method public android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
-    method public android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
-    method public int getFormatWidth();
-    method public int getGroupingSize();
-    method public java.math.MathContext getMathContext();
-    method public android.icu.math.MathContext getMathContextICU();
-    method public int getMaximumSignificantDigits();
-    method public byte getMinimumExponentDigits();
-    method public int getMinimumSignificantDigits();
-    method public int getMultiplier();
-    method public java.lang.String getNegativePrefix();
-    method public java.lang.String getNegativeSuffix();
-    method public char getPadCharacter();
-    method public int getPadPosition();
-    method public int getParseMaxDigits();
-    method public java.lang.String getPositivePrefix();
-    method public java.lang.String getPositiveSuffix();
-    method public java.math.BigDecimal getRoundingIncrement();
-    method public int getSecondaryGroupingSize();
-    method public boolean isDecimalPatternMatchRequired();
-    method public boolean isDecimalSeparatorAlwaysShown();
-    method public boolean isExponentSignAlwaysShown();
-    method public boolean isParseBigDecimal();
-    method public boolean isScientificNotation();
+    method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
+    method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
+    method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
+    method public synchronized int getFormatWidth();
+    method public synchronized int getGroupingSize();
+    method public synchronized java.math.MathContext getMathContext();
+    method public synchronized android.icu.math.MathContext getMathContextICU();
+    method public synchronized int getMaximumSignificantDigits();
+    method public synchronized byte getMinimumExponentDigits();
+    method public synchronized int getMinimumSignificantDigits();
+    method public synchronized int getMultiplier();
+    method public synchronized java.lang.String getNegativePrefix();
+    method public synchronized java.lang.String getNegativeSuffix();
+    method public synchronized char getPadCharacter();
+    method public synchronized int getPadPosition();
+    method public deprecated int getParseMaxDigits();
+    method public synchronized java.lang.String getPositivePrefix();
+    method public synchronized java.lang.String getPositiveSuffix();
+    method public synchronized java.math.BigDecimal getRoundingIncrement();
+    method public synchronized int getSecondaryGroupingSize();
+    method public synchronized boolean isDecimalPatternMatchRequired();
+    method public synchronized boolean isDecimalSeparatorAlwaysShown();
+    method public synchronized boolean isExponentSignAlwaysShown();
+    method public synchronized boolean isParseBigDecimal();
+    method public synchronized boolean isScientificNotation();
     method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
-    method public void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
-    method public void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
-    method public void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
-    method public void setDecimalPatternMatchRequired(boolean);
-    method public void setDecimalSeparatorAlwaysShown(boolean);
-    method public void setExponentSignAlwaysShown(boolean);
-    method public void setFormatWidth(int);
-    method public void setGroupingSize(int);
-    method public void setMathContext(java.math.MathContext);
-    method public void setMathContextICU(android.icu.math.MathContext);
-    method public void setMaximumSignificantDigits(int);
-    method public void setMinimumExponentDigits(byte);
-    method public void setMinimumSignificantDigits(int);
-    method public void setMultiplier(int);
-    method public void setNegativePrefix(java.lang.String);
-    method public void setNegativeSuffix(java.lang.String);
-    method public void setPadCharacter(char);
-    method public void setPadPosition(int);
-    method public void setParseBigDecimal(boolean);
-    method public void setParseMaxDigits(int);
-    method public void setPositivePrefix(java.lang.String);
-    method public void setPositiveSuffix(java.lang.String);
-    method public void setRoundingIncrement(java.math.BigDecimal);
-    method public void setRoundingIncrement(android.icu.math.BigDecimal);
-    method public void setRoundingIncrement(double);
-    method public void setScientificNotation(boolean);
-    method public void setSecondaryGroupingSize(int);
-    method public void setSignificantDigitsUsed(boolean);
-    method public java.lang.String toLocalizedPattern();
-    method public java.lang.String toPattern();
+    method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
+    method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
+    method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
+    method public synchronized void setDecimalPatternMatchRequired(boolean);
+    method public synchronized void setDecimalSeparatorAlwaysShown(boolean);
+    method public synchronized void setExponentSignAlwaysShown(boolean);
+    method public synchronized void setFormatWidth(int);
+    method public synchronized void setGroupingSize(int);
+    method public synchronized void setMathContext(java.math.MathContext);
+    method public synchronized void setMathContextICU(android.icu.math.MathContext);
+    method public synchronized void setMaximumSignificantDigits(int);
+    method public synchronized void setMinimumExponentDigits(byte);
+    method public synchronized void setMinimumSignificantDigits(int);
+    method public synchronized void setMultiplier(int);
+    method public synchronized void setNegativePrefix(java.lang.String);
+    method public synchronized void setNegativeSuffix(java.lang.String);
+    method public synchronized void setPadCharacter(char);
+    method public synchronized void setPadPosition(int);
+    method public synchronized void setParseBigDecimal(boolean);
+    method public deprecated void setParseMaxDigits(int);
+    method public synchronized void setPositivePrefix(java.lang.String);
+    method public synchronized void setPositiveSuffix(java.lang.String);
+    method public synchronized void setRoundingIncrement(java.math.BigDecimal);
+    method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
+    method public synchronized void setRoundingIncrement(double);
+    method public synchronized void setScientificNotation(boolean);
+    method public synchronized void setSecondaryGroupingSize(int);
+    method public synchronized void setSignificantDigitsUsed(boolean);
+    method public synchronized java.lang.String toLocalizedPattern();
+    method public synchronized java.lang.String toPattern();
     field public static final int PAD_AFTER_PREFIX = 1; // 0x1
     field public static final int PAD_AFTER_SUFFIX = 3; // 0x3
     field public static final int PAD_BEFORE_PREFIX = 0; // 0x0
@@ -17590,6 +17594,8 @@
     method public java.lang.String combineDateAndTime(java.lang.String, java.lang.String);
     method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.RelativeUnit);
     method public java.lang.String format(android.icu.text.RelativeDateTimeFormatter.Direction, android.icu.text.RelativeDateTimeFormatter.AbsoluteUnit);
+    method public java.lang.String format(double, android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit);
+    method public java.lang.String formatNumeric(double, android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit);
     method public android.icu.text.DisplayContext getCapitalizationContext();
     method public android.icu.text.RelativeDateTimeFormatter.Style getFormatStyle();
     method public static android.icu.text.RelativeDateTimeFormatter getInstance();
@@ -17629,6 +17635,26 @@
     enum_constant public static final android.icu.text.RelativeDateTimeFormatter.Direction THIS;
   }
 
+  public static final class RelativeDateTimeFormatter.RelativeDateTimeUnit extends java.lang.Enum {
+    method public static android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit valueOf(java.lang.String);
+    method public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit[] values();
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit DAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit FRIDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit HOUR;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit MINUTE;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit MONDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit MONTH;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit QUARTER;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit SATURDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit SECOND;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit SUNDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit THURSDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit TUESDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit WEDNESDAY;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit WEEK;
+    enum_constant public static final android.icu.text.RelativeDateTimeFormatter.RelativeDateTimeUnit YEAR;
+  }
+
   public static final class RelativeDateTimeFormatter.RelativeUnit extends java.lang.Enum {
     method public static android.icu.text.RelativeDateTimeFormatter.RelativeUnit valueOf(java.lang.String);
     method public static final android.icu.text.RelativeDateTimeFormatter.RelativeUnit[] values();
@@ -18699,6 +18725,7 @@
     field public static final android.icu.util.MeasureUnit FOOT;
     field public static final android.icu.util.MeasureUnit FURLONG;
     field public static final android.icu.util.MeasureUnit GALLON;
+    field public static final android.icu.util.MeasureUnit GALLON_IMPERIAL;
     field public static final android.icu.util.MeasureUnit GENERIC_TEMPERATURE;
     field public static final android.icu.util.MeasureUnit GIGABIT;
     field public static final android.icu.util.MeasureUnit GIGABYTE;
@@ -18747,11 +18774,13 @@
     field public static final android.icu.util.MeasureUnit MICROSECOND;
     field public static final android.icu.util.MeasureUnit MILE;
     field public static final android.icu.util.MeasureUnit MILE_PER_GALLON;
+    field public static final android.icu.util.MeasureUnit MILE_PER_GALLON_IMPERIAL;
     field public static final android.icu.util.MeasureUnit MILE_PER_HOUR;
     field public static final android.icu.util.MeasureUnit MILE_SCANDINAVIAN;
     field public static final android.icu.util.MeasureUnit MILLIAMPERE;
     field public static final android.icu.util.MeasureUnit MILLIBAR;
     field public static final android.icu.util.MeasureUnit MILLIGRAM;
+    field public static final android.icu.util.MeasureUnit MILLIGRAM_PER_DECILITER;
     field public static final android.icu.util.MeasureUnit MILLILITER;
     field public static final android.icu.util.MeasureUnit MILLIMETER;
     field public static final android.icu.util.MeasureUnit MILLIMETER_OF_MERCURY;
@@ -19055,7 +19084,7 @@
     field public static final int JAVA_TIME = 0; // 0x0
     field public static final int MAC_OLD_TIME = 5; // 0x5
     field public static final int MAC_TIME = 6; // 0x6
-    field public static final int MAX_SCALE = 10; // 0xa
+    field public static final deprecated int MAX_SCALE = 10; // 0xa
     field public static final int TO_MAX_VALUE = 5; // 0x5
     field public static final int TO_MIN_VALUE = 4; // 0x4
     field public static final int UNITS_VALUE = 0; // 0x0
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index dfd5996..44c2667 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -415,7 +415,8 @@
           gatt = mBluetoothManager.getBluetoothGatt();
         } catch (RemoteException e) {
           Log.e(TAG, "Failed to get Bluetooth gatt - ", e);
-          throw new IllegalStateException("Failed to get Bluetooth");
+          postStartSetFailure(handler, callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
+          return;
         }
 
         IAdvertisingSetCallback wrapped = wrap(callback, handler);
@@ -429,7 +430,8 @@
                                      periodicData, duration, maxExtendedAdvertisingEvents, wrapped);
         } catch (RemoteException e) {
           Log.e(TAG, "Failed to start advertising set - ", e);
-          throw new IllegalStateException("Failed to start advertising set");
+          postStartSetFailure(handler, callback, AdvertiseCallback.ADVERTISE_FAILED_INTERNAL_ERROR);
+          return;
         }
     }
 
@@ -453,8 +455,7 @@
             gatt.stopAdvertisingSet(wrapped);
        } catch (RemoteException e) {
             Log.e(TAG, "Failed to stop advertising - ", e);
-            throw new IllegalStateException("Failed to stop advertising");
-        }
+       }
     }
 
     /**
@@ -648,6 +649,16 @@
         };
     }
 
+    private void postStartSetFailure(Handler handler, final AdvertisingSetCallback callback,
+        final int error) {
+        handler.post(new Runnable() {
+              @Override
+              public void run() {
+                  callback.onAdvertisingSetStarted(null, 0, error);
+              }
+          });
+    }
+
     private void postStartFailure(final AdvertiseCallback callback, final int error) {
         mHandler.post(new Runnable() {
             @Override
diff --git a/core/java/android/net/ITetheringStatsProvider.aidl b/core/java/android/net/ITetheringStatsProvider.aidl
index 769086d..1aeabc1 100644
--- a/core/java/android/net/ITetheringStatsProvider.aidl
+++ b/core/java/android/net/ITetheringStatsProvider.aidl
@@ -19,7 +19,7 @@
 import android.net.NetworkStats;
 
 /**
- * Interface that allows NetworkManagementService to query for tethering statistics.
+ * Interface for NetworkManagementService to query tethering statistics and set data limits.
  *
  * TODO: this does not really need to be an interface since Tethering runs in the same process
  * as NetworkManagementService. Consider refactoring Tethering to use direct access to
@@ -29,5 +29,14 @@
  * @hide
  */
 interface ITetheringStatsProvider {
+    // Returns cumulative statistics for all tethering sessions since boot, on all upstreams.
     NetworkStats getTetherStats();
+
+    // Sets the interface quota for the specified upstream interface. This is defined as the number
+    // of bytes, starting from zero and counting from now, after which data should stop being
+    // forwarded to/from the specified upstream. A value of QUOTA_UNLIMITED means there is no limit.
+    void setInterfaceQuota(String iface, long quotaBytes);
+
+    // Indicates that no data usage limit is set.
+    const int QUOTA_UNLIMITED = -1;
 }
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index 6b4f2d5..6e2654e 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -20,6 +20,8 @@
 import android.os.Parcelable;
 import android.util.Pair;
 
+import java.net.Inet4Address;
+import java.net.Inet6Address;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
 import java.util.Arrays;
@@ -185,6 +187,20 @@
     }
 
     /**
+     * @hide
+     */
+    public boolean isIPv6() {
+        return getAddress() instanceof Inet6Address;
+    }
+
+    /**
+     * @hide
+     */
+    public boolean isIPv4() {
+        return getAddress() instanceof Inet4Address;
+    }
+
+    /**
      * Returns a string representation of this {@code IpPrefix}.
      *
      * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}.
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 62de991..bcfe938 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -76,7 +76,7 @@
      * RFC 6724 section 3.2.
      * @hide
      */
-    static int scopeForUnicastAddress(InetAddress addr) {
+    private static int scopeForUnicastAddress(InetAddress addr) {
         if (addr.isAnyLocalAddress()) {
             return RT_SCOPE_HOST;
         }
@@ -101,7 +101,7 @@
      * Per RFC 4193 section 8, fc00::/7 identifies these addresses.
      */
     private boolean isIPv6ULA() {
-        if (address instanceof Inet6Address) {
+        if (isIPv6()) {
             byte[] bytes = address.getAddress();
             return ((bytes[0] & (byte)0xfe) == (byte)0xfc);
         }
@@ -109,13 +109,29 @@
     }
 
     /**
+     * @return true if the address is IPv6.
+     * @hide
+     */
+    public boolean isIPv6() {
+        return address instanceof Inet6Address;
+    }
+
+    /**
+     * @return true if the address is IPv4 or is a mapped IPv4 address.
+     * @hide
+     */
+    public boolean isIPv4() {
+        return address instanceof Inet4Address;
+    }
+
+    /**
      * Utility function for the constructors.
      */
     private void init(InetAddress address, int prefixLength, int flags, int scope) {
         if (address == null ||
                 address.isMulticastAddress() ||
                 prefixLength < 0 ||
-                ((address instanceof Inet4Address) && prefixLength > 32) ||
+                (address instanceof Inet4Address && prefixLength > 32) ||
                 (prefixLength > 128)) {
             throw new IllegalArgumentException("Bad LinkAddress params " + address +
                     "/" + prefixLength);
@@ -184,6 +200,7 @@
      */
     public LinkAddress(String address, int flags, int scope) {
         // This may throw an IllegalArgumentException; catching it is the caller's responsibility.
+        // TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
         Pair<InetAddress, Integer> ipAndMask = NetworkUtils.parseIpAndMask(address);
         init(ipAndMask.first, ipAndMask.second, flags, scope);
     }
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 0b92893..4bb8844 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -770,7 +770,6 @@
 
         StringJoiner joiner = new StringJoiner(", ");
 
-        // TODO: consider only enforcing that capabilities are not removed, allowing addition.
         // Ignore NOT_METERED being added or removed as it is effectively dynamic. http://b/63326103
         // TODO: properly support NOT_METERED as a mutable and requestable capability.
         final long mask = ~MUTABLE_CAPABILITIES & ~(1 << NET_CAPABILITY_NOT_METERED);
diff --git a/core/java/com/android/internal/net/OWNERS b/core/java/com/android/internal/net/OWNERS
new file mode 100644
index 0000000..7cb32ff
--- /dev/null
+++ b/core/java/com/android/internal/net/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+ek@google.com
+hugobenichi@google.com
+jsharkey@google.com
+lorenzo@google.com
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 24e1b33..bc27663 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -41,6 +41,8 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
+import android.system.StructCapUserData;
+import android.system.StructCapUserHeader;
 import android.text.Hyphenator;
 import android.util.EventLog;
 import android.util.Log;
@@ -80,7 +82,6 @@
 
     private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
     private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
-    private static final String PROPERTY_RUNNING_IN_CONTAINER = "ro.boot.container";
 
     private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
     private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
@@ -567,12 +568,20 @@
             OsConstants.CAP_SYS_RESOURCE,
             OsConstants.CAP_SYS_TIME,
             OsConstants.CAP_SYS_TTY_CONFIG,
-            OsConstants.CAP_WAKE_ALARM
+            OsConstants.CAP_WAKE_ALARM,
+            OsConstants.CAP_BLOCK_SUSPEND
         );
-        /* Containers run without this capability, so avoid setting it in that case */
-        if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
-            capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
+        /* Containers run without some capabilities, so drop any caps that are not available. */
+        StructCapUserHeader header = new StructCapUserHeader(
+                OsConstants._LINUX_CAPABILITY_VERSION_3, 0);
+        StructCapUserData[] data;
+        try {
+            data = Os.capget(header);
+        } catch (ErrnoException ex) {
+            throw new RuntimeException("Failed to capget()", ex);
         }
+        capabilities &= ((long) data[0].effective) | (((long) data[1].effective) << 32);
+
         /* Hardcoded command line to start the system server */
         String args[] = {
             "--setuid=1000",
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index 0c23797..40d49b7 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -83,12 +83,6 @@
       mSize(size),
       mOwnsBuffer(true),
       mHandle(0) {
-    jclass clazz = env->GetObjectClass(thiz);
-    CHECK(clazz != NULL);
-
-    mClass = (jclass)env->NewGlobalRef(clazz);
-    mObject = env->NewWeakGlobalRef(thiz);
-
     if (size > 0) {
         mBuffer = malloc(size);
     }
@@ -99,14 +93,6 @@
         free(mBuffer);
         mBuffer = nullptr;
     }
-
-    JNIEnv *env = AndroidRuntime::getJNIEnv();
-
-    env->DeleteWeakGlobalRef(mObject);
-    mObject = NULL;
-
-    env->DeleteGlobalRef(mClass);
-    mClass = NULL;
 }
 
 void JHwBlob::setTo(const void *ptr, size_t handle) {
diff --git a/core/jni/android_os_HwBlob.h b/core/jni/android_os_HwBlob.h
index 0920488..39393cb 100644
--- a/core/jni/android_os_HwBlob.h
+++ b/core/jni/android_os_HwBlob.h
@@ -70,9 +70,6 @@
         sp<JHwBlob> mBlob;
     };
 
-    jclass mClass;
-    jobject mObject;
-
     void *mBuffer;
     size_t mSize;
     bool mOwnsBuffer;
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index b412b6a..9494fb8 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -166,10 +166,6 @@
       mOwnsParcel(false),
       mTransactCallback(nullptr),
       mWasSent(false) {
-    jclass clazz = env->GetObjectClass(thiz);
-    CHECK(clazz != NULL);
-
-    mObject = env->NewWeakGlobalRef(thiz);
 }
 
 JHwParcel::~JHwParcel() {
@@ -178,9 +174,6 @@
     mStorage.release(env);
 
     setParcel(NULL, false /* assumeOwnership */);
-
-    env->DeleteWeakGlobalRef(mObject);
-    mObject = NULL;
 }
 
 hardware::Parcel *JHwParcel::getParcel() {
diff --git a/core/jni/android_os_HwParcel.h b/core/jni/android_os_HwParcel.h
index f6e6100..2c26993 100644
--- a/core/jni/android_os_HwParcel.h
+++ b/core/jni/android_os_HwParcel.h
@@ -53,8 +53,6 @@
     virtual ~JHwParcel();
 
 private:
-    jobject mObject;
-
     hardware::Parcel *mParcel;
     bool mOwnsParcel;
 
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index dba8194..914688e 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -674,6 +674,22 @@
   }
   return pid;
 }
+
+static uint64_t GetEffectiveCapabilityMask(JNIEnv* env) {
+    __user_cap_header_struct capheader;
+    memset(&capheader, 0, sizeof(capheader));
+    capheader.version = _LINUX_CAPABILITY_VERSION_3;
+    capheader.pid = 0;
+
+    __user_cap_data_struct capdata[2];
+    if (capget(&capheader, &capdata[0]) == -1) {
+        ALOGE("capget failed: %s", strerror(errno));
+        RuntimeAbort(env, __LINE__, "capget failed");
+    }
+
+    return capdata[0].effective |
+           (static_cast<uint64_t>(capdata[1].effective) << 32);
+}
 }  // anonymous namespace
 
 namespace android {
@@ -724,6 +740,10 @@
       capabilities |= (1LL << CAP_BLOCK_SUSPEND);
     }
 
+    // Containers run without some capabilities, so drop any caps that are not
+    // available.
+    capabilities &= GetEffectiveCapabilityMask(env);
+
     return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
             rlimits, capabilities, capabilities, mount_external, se_info,
             se_name, false, fdsToClose, fdsToIgnore, instructionSet, appDataDir);
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index af78669..78ffb5b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2783,4 +2783,8 @@
 
     <!-- Package name of the default cell broadcast receiver -->
     <string name="config_defaultCellBroadcastReceiverPkg" translatable="false">com.android.cellbroadcastreceiver</string>
+    <!-- When true, indicates that the vendor's IMS implementation requires a workaround when
+     sending a request to enable or disable the camera while the video session is also
+     paused. -->
+    <bool name="config_useVideoPauseWorkaround">false</bool>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c53093f..4bf5043 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2795,4 +2795,5 @@
   <java-symbol type="string" name="etws_primary_default_message_test" />
 
   <java-symbol type="string" name="etws_primary_default_message_others" />
+  <java-symbol type="bool" name="config_useVideoPauseWorkaround" />
 </resources>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index c1a3f86..d556b64 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -467,6 +467,12 @@
         loadingContent.layout(0, 0, loadingContent.getMeasuredWidth(),
                 loadingContent.getMeasuredHeight());
 
+        // To create a bitmap, height & width should be larger than 0
+        if (mPageContentHeight <= 0 || mPageContentWidth <= 0) {
+            Log.w(LOG_TAG, "Unable to create bitmap, height or width smaller than 0!");
+            return;
+        }
+
         Bitmap loadingBitmap = Bitmap.createBitmap(mPageContentWidth, mPageContentHeight,
                 Bitmap.Config.ARGB_8888);
         loadingContent.draw(new Canvas(loadingBitmap));
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8972802..0babbc8 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -4702,11 +4702,15 @@
      */
     private void updateCapabilities(
             int oldScore, NetworkAgentInfo nai, NetworkCapabilities networkCapabilities) {
-        // Sanity check: a NetworkAgent should not change its static capabilities or parameters.
-        if (nai.everConnected) {
+        // Once a NetworkAgent is connected, complain if some immutable capabilities are removed.
+        if (nai.everConnected &&
+                !nai.networkCapabilities.satisfiedByNetworkCapabilities(networkCapabilities)) {
+            // TODO: consider not complaining when a network agent degrade its capabilities if this
+            // does not cause any request (that is not a listen) currently matching that agent to
+            // stop being matched by the updated agent.
             String diff = nai.networkCapabilities.describeImmutableDifferences(networkCapabilities);
             if (!TextUtils.isEmpty(diff)) {
-                Slog.wtf(TAG, "BUG: " + nai + " changed immutable capabilities:" + diff);
+                Slog.wtf(TAG, "BUG: " + nai + " lost immutable capabilities:" + diff);
             }
         }
 
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index ab7dacc..3056831 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -142,6 +142,17 @@
             }
             mCurrent--;
         }
+
+        @Override
+        public String toString() {
+            return new StringBuilder()
+                    .append("{mCurrent=")
+                    .append(mCurrent)
+                    .append(", mMax=")
+                    .append(mMax)
+                    .append("}")
+                    .toString();
+        }
     }
 
     private static final class UserQuotaTracker {
@@ -159,6 +170,19 @@
             public final ResourceTracker socket = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS);
             public final ResourceTracker transform = new ResourceTracker(MAX_NUM_TRANSFORMS);
             public final ResourceTracker spi = new ResourceTracker(MAX_NUM_SPIS);
+
+            @Override
+            public String toString() {
+                return new StringBuilder()
+                        .append("{socket=")
+                        .append(socket)
+                        .append(", transform=")
+                        .append(transform)
+                        .append(", spi=")
+                        .append(spi)
+                        .append("}")
+                        .toString();
+            }
         }
 
         private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
@@ -172,6 +196,11 @@
             }
             return r;
         }
+
+        @Override
+        public String toString() {
+            return mUserRecords.toString();
+        }
     }
 
     private final UserQuotaTracker mUserQuotaTracker = new UserQuotaTracker();
@@ -909,6 +938,8 @@
         pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead"));
         pw.println();
 
+        pw.println("mUserQuotaTracker:");
+        pw.println(mUserQuotaTracker);
         pw.println("mTransformRecords:");
         pw.println(mTransformRecords);
         pw.println("mUdpSocketRecords:");
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 097202b..3d638be 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1538,6 +1538,17 @@
             } catch (NativeDaemonConnectorException e) {
                 throw e.rethrowAsParcelableException();
             }
+
+            synchronized (mTetheringStatsProviders) {
+                for (ITetheringStatsProvider provider : mTetheringStatsProviders.keySet()) {
+                    try {
+                        provider.setInterfaceQuota(iface, quotaBytes);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Problem setting tethering data limit on provider " +
+                                mTetheringStatsProviders.get(provider) + ": " + e);
+                    }
+                }
+            }
         }
     }
 
@@ -1564,6 +1575,17 @@
             } catch (NativeDaemonConnectorException e) {
                 throw e.rethrowAsParcelableException();
             }
+
+            synchronized (mTetheringStatsProviders) {
+                for (ITetheringStatsProvider provider : mTetheringStatsProviders.keySet()) {
+                    try {
+                        provider.setInterfaceQuota(iface, ITetheringStatsProvider.QUOTA_UNLIMITED);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Problem removing tethering data limit on provider " +
+                                mTetheringStatsProviders.get(provider) + ": " + e);
+                    }
+                }
+            }
         }
     }
 
@@ -1823,6 +1845,11 @@
             }
             return stats;
         }
+
+        @Override
+        public void setInterfaceQuota(String iface, long quotaBytes) {
+            // Do nothing. netd is already informed of quota changes in setInterfaceQuota.
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 1a5ff77..55e290a 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -46,7 +46,6 @@
 import java.util.HashSet;
 import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -58,8 +57,6 @@
 public class OffloadController {
     private static final String TAG = OffloadController.class.getSimpleName();
 
-    private static final int STATS_FETCH_TIMEOUT_MS = 1000;
-
     private final Handler mHandler;
     private final OffloadHardwareInterface mHwInterface;
     private final ContentResolver mContentResolver;
@@ -76,9 +73,17 @@
     private Set<String> mLastLocalPrefixStrs;
 
     // Maps upstream interface names to offloaded traffic statistics.
+    // Always contains the latest value received from the hardware for each interface, regardless of
+    // whether offload is currently running on that interface.
     private HashMap<String, OffloadHardwareInterface.ForwardedStats>
             mForwardedStats = new HashMap<>();
 
+    // Maps upstream interface names to interface quotas.
+    // Always contains the latest value received from the framework for each interface, regardless
+    // of whether offload is currently running (or is even supported) on that interface. Only
+    // includes upstream interfaces that have a quota set.
+    private HashMap<String, Long> mInterfaceQuotas = new HashMap<>();
+
     public OffloadController(Handler h, OffloadHardwareInterface hwi,
             ContentResolver contentResolver, INetworkManagementService nms, SharedLog log) {
         mHandler = h;
@@ -177,36 +182,38 @@
         @Override
         public NetworkStats getTetherStats() {
             NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
-            CountDownLatch latch = new CountDownLatch(1);
 
-            mHandler.post(() -> {
-                try {
-                    NetworkStats.Entry entry = new NetworkStats.Entry();
-                    entry.set = SET_DEFAULT;
-                    entry.tag = TAG_NONE;
-                    entry.uid = UID_TETHERING;
+            // We can't just post to mHandler because we are mostly (but not always) called by
+            // NetworkStatsService#performPollLocked, which is (currently) on the same thread as us.
+            mHandler.runWithScissors(() -> {
+                NetworkStats.Entry entry = new NetworkStats.Entry();
+                entry.set = SET_DEFAULT;
+                entry.tag = TAG_NONE;
+                entry.uid = UID_TETHERING;
 
-                    updateStatsForCurrentUpstream();
+                updateStatsForCurrentUpstream();
 
-                    for (String iface : mForwardedStats.keySet()) {
-                        entry.iface = iface;
-                        entry.rxBytes = mForwardedStats.get(iface).rxBytes;
-                        entry.txBytes = mForwardedStats.get(iface).txBytes;
-                        stats.addValues(entry);
-                    }
-                } finally {
-                    latch.countDown();
+                for (String iface : mForwardedStats.keySet()) {
+                    entry.iface = iface;
+                    entry.rxBytes = mForwardedStats.get(iface).rxBytes;
+                    entry.txBytes = mForwardedStats.get(iface).txBytes;
+                    stats.addValues(entry);
                 }
-            });
-
-            try {
-                latch.await(STATS_FETCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
-            } catch (InterruptedException e) {
-                mLog.e("Tethering stats fetch timed out after " + STATS_FETCH_TIMEOUT_MS + "ms");
-            }
+            }, 0);
 
             return stats;
         }
+
+        public void setInterfaceQuota(String iface, long quotaBytes) {
+            mHandler.post(() -> {
+                if (quotaBytes == ITetheringStatsProvider.QUOTA_UNLIMITED) {
+                    mInterfaceQuotas.remove(iface);
+                } else {
+                    mInterfaceQuotas.put(iface, quotaBytes);
+                }
+                maybeUpdateDataLimit(iface);
+            });
+        }
     }
 
     private void maybeUpdateStats(String iface) {
@@ -220,6 +227,22 @@
         mForwardedStats.get(iface).add(mHwInterface.getForwardedStats(iface));
     }
 
+    private boolean maybeUpdateDataLimit(String iface) {
+        // setDataLimit may only be called while offload is occuring on this upstream.
+        if (!started() ||
+                mUpstreamLinkProperties == null ||
+                !TextUtils.equals(iface, mUpstreamLinkProperties.getInterfaceName())) {
+            return true;
+        }
+
+        Long limit = mInterfaceQuotas.get(iface);
+        if (limit == null) {
+            limit = Long.MAX_VALUE;
+        }
+
+        return mHwInterface.setDataLimit(iface, limit);
+    }
+
     private void updateStatsForCurrentUpstream() {
         if (mUpstreamLinkProperties != null) {
             maybeUpdateStats(mUpstreamLinkProperties.getInterfaceName());
@@ -309,8 +332,21 @@
             }
         }
 
-        return mHwInterface.setUpstreamParameters(
+        boolean success = mHwInterface.setUpstreamParameters(
                 iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways));
+
+        if (!success) {
+           return success;
+        }
+
+        // Data limits can only be set once offload is running on the upstream.
+        success = maybeUpdateDataLimit(iface);
+        if (!success) {
+            mLog.log("Setting data limit for " + iface + " failed, disabling offload.");
+            stop();
+        }
+
+        return success;
     }
 
     private boolean computeAndPushLocalPrefixes() {
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 4df566f..86ff0a6 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -188,6 +188,27 @@
         return results.success;
     }
 
+    public boolean setDataLimit(String iface, long limit) {
+
+        final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit);
+
+        final CbResults results = new CbResults();
+        try {
+            mOffloadControl.setDataLimit(
+                    iface, limit,
+                    (boolean success, String errMsg) -> {
+                        results.success = success;
+                        results.errMsg = errMsg;
+                    });
+        } catch (RemoteException e) {
+            record(logmsg, e);
+            return false;
+        }
+
+        record(logmsg, results);
+        return results.success;
+    }
+
     public boolean setUpstreamParameters(
             String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
         iface = (iface != null) ? iface : NO_INTERFACE_NAME;
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 7401dda..79064bf 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -100,6 +100,7 @@
     private static final String SESSION_ADD_CS_ADAPTER = "CS.aCSA";
     private static final String SESSION_REMOVE_CS_ADAPTER = "CS.rCSA";
     private static final String SESSION_CREATE_CONN = "CS.crCo";
+    private static final String SESSION_CREATE_CONN_COMPLETE = "CS.crCoC";
     private static final String SESSION_CREATE_CONN_FAILED = "CS.crCoF";
     private static final String SESSION_ABORT = "CS.ab";
     private static final String SESSION_ANSWER = "CS.an";
@@ -152,6 +153,7 @@
     private static final int MSG_ON_START_RTT = 26;
     private static final int MSG_ON_STOP_RTT = 27;
     private static final int MSG_RTT_UPGRADE_RESPONSE = 28;
+    private static final int MSG_CREATE_CONNECTION_COMPLETE = 29;
 
     private static Connection sNullConnection;
 
@@ -221,6 +223,19 @@
         }
 
         @Override
+        public void createConnectionComplete(String id, Session.Info sessionInfo) {
+            Log.startSession(sessionInfo, SESSION_CREATE_CONN_COMPLETE);
+            try {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = id;
+                args.arg2 = Log.createSubsession();
+                mHandler.obtainMessage(MSG_CREATE_CONNECTION_COMPLETE, args).sendToTarget();
+            } finally {
+                Log.endSession();
+            }
+        }
+
+        @Override
         public void createConnectionFailed(
                 PhoneAccountHandle connectionManagerPhoneAccount,
                 String callId,
@@ -630,6 +645,33 @@
                     }
                     break;
                 }
+                case MSG_CREATE_CONNECTION_COMPLETE: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    Log.continueSession((Session) args.arg2,
+                            SESSION_HANDLER + SESSION_CREATE_CONN_COMPLETE);
+                    try {
+                        final String id = (String) args.arg1;
+                        if (!mAreAccountsInitialized) {
+                            Log.d(this, "Enqueueing pre-init request %s", id);
+                            mPreInitializationConnectionRequests.add(
+                                    new android.telecom.Logging.Runnable(
+                                            SESSION_HANDLER + SESSION_CREATE_CONN_COMPLETE
+                                                    + ".pICR",
+                                            null /*lock*/) {
+                                        @Override
+                                        public void loggedRun() {
+                                            notifyCreateConnectionComplete(id);
+                                        }
+                                    }.prepare());
+                        } else {
+                            notifyCreateConnectionComplete(id);
+                        }
+                    } finally {
+                        args.recycle();
+                        Log.endSession();
+                    }
+                    break;
+                }
                 case MSG_CREATE_CONNECTION_FAILED: {
                     SomeArgs args = (SomeArgs) msg.obj;
                     Log.continueSession((Session) args.arg3, SESSION_HANDLER +
@@ -1373,6 +1415,17 @@
         }
     }
 
+    /**
+     * Called by Telecom when the creation of a new Connection has completed and it is now added
+     * to Telecom.
+     * @param callId The ID of the connection.
+     */
+    private void notifyCreateConnectionComplete(final String callId) {
+        Log.i(this, "notifyCreateConnectionComplete %s", callId);
+        onCreateConnectionComplete(findConnectionForAction(callId,
+                "notifyCreateConnectionComplete"));
+    }
+
     private void abort(String callId) {
         Log.d(this, "abort %s", callId);
         findConnectionForAction(callId, "abort").onAbort();
@@ -1837,6 +1890,18 @@
     }
 
     /**
+     * Called after the {@link Connection} returned by
+     * {@link #onCreateIncomingConnection(PhoneAccountHandle, ConnectionRequest)}
+     * or {@link #onCreateOutgoingConnection(PhoneAccountHandle, ConnectionRequest)} has been
+     * added to the {@link ConnectionService} and sent to Telecom.
+     *
+     * @param connection the {@link Connection}.
+     * @hide
+     */
+    public void onCreateConnectionComplete(Connection connection) {
+    }
+
+    /**
      * Called by Telecom to inform the {@link ConnectionService} that its request to create a new
      * incoming {@link Connection} was denied.
      * <p>
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index e6b567e..dcf5c27 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -83,6 +83,13 @@
      */
     public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF";
 
+    /**
+     * Reason code (returned via {@link #getReason()}), which indicates that the video telephony
+     * call was disconnected because IMS access is blocked.
+     * @hide
+     */
+    public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED";
+
     private int mDisconnectCode;
     private CharSequence mDisconnectLabel;
     private CharSequence mDisconnectDescription;
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index c631d08..e428286 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -47,6 +47,8 @@
             boolean isUnknown,
             in Session.Info sessionInfo);
 
+    void createConnectionComplete(String callId, in Session.Info sessionInfo);
+
     void createConnectionFailed(in PhoneAccountHandle connectionManagerPhoneAccount, String callId,
             in ConnectionRequest request, boolean isIncoming, in Session.Info sessionInfo);
 
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 5fb83ab..e448fb2 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -795,34 +795,57 @@
         return rtString;
     }
 
+    /**
+     * Convert RIL Service State to String
+     *
+     * @param serviceState
+     * @return String representation of the ServiceState
+     *
+     * @hide
+     */
+    public static String rilServiceStateToString(int serviceState) {
+        switch(serviceState) {
+            case STATE_IN_SERVICE:
+                return "IN_SERVICE";
+            case STATE_OUT_OF_SERVICE:
+                return "OUT_OF_SERVICE";
+            case STATE_EMERGENCY_ONLY:
+                return "EMERGENCY_ONLY";
+            case STATE_POWER_OFF:
+                return "POWER_OFF";
+            default:
+                return "UNKNOWN";
+        }
+    }
+
     @Override
     public String toString() {
-        String radioTechnology = rilRadioTechnologyToString(mRilVoiceRadioTechnology);
-        String dataRadioTechnology = rilRadioTechnologyToString(mRilDataRadioTechnology);
-
-        return (mVoiceRegState + " " + mDataRegState
-                + " "
-                + "voice " + getRoamingLogString(mVoiceRoamingType)
-                + " "
-                + "data " + getRoamingLogString(mDataRoamingType)
-                + " " + mVoiceOperatorAlphaLong
-                + " " + mVoiceOperatorAlphaShort
-                + " " + mVoiceOperatorNumeric
-                + " " + mDataOperatorAlphaLong
-                + " " + mDataOperatorAlphaShort
-                + " " + mDataOperatorNumeric
-                + " " + (mIsManualNetworkSelection ? "(manual)" : "")
-                + " " + radioTechnology
-                + " " + dataRadioTechnology
-                + " " + (mCssIndicator ? "CSS supported" : "CSS not supported")
-                + " " + mNetworkId
-                + " " + mSystemId
-                + " RoamInd=" + mCdmaRoamingIndicator
-                + " DefRoamInd=" + mCdmaDefaultRoamingIndicator
-                + " EmergOnly=" + mIsEmergencyOnly
-                + " IsDataRoamingFromRegistration=" + mIsDataRoamingFromRegistration
-                + " IsUsingCarrierAggregation=" + mIsUsingCarrierAggregation
-                + " mLteEarfcnRsrpBoost=" + mLteEarfcnRsrpBoost);
+        return new StringBuilder().append("{mVoiceRegState=").append(mVoiceRegState)
+            .append("(" + rilServiceStateToString(mVoiceRegState) + ")")
+            .append(", mDataRegState=").append(mDataRegState)
+            .append("(" + rilServiceStateToString(mDataRegState) + ")")
+            .append(", mVoiceRoamingType=").append(getRoamingLogString(mVoiceRoamingType))
+            .append(", mDataRoamingType=").append(getRoamingLogString(mDataRoamingType))
+            .append(", mVoiceOperatorAlphaLong=").append(mVoiceOperatorAlphaLong)
+            .append(", mVoiceOperatorAlphaShort=").append(mVoiceOperatorAlphaShort)
+            .append(", mDataOperatorAlphaLong=").append(mDataOperatorAlphaLong)
+            .append(", mDataOperatorAlphaShort=").append(mDataOperatorAlphaShort)
+            .append(", isManualNetworkSelection=").append(mIsManualNetworkSelection)
+            .append(mIsManualNetworkSelection ? "(manual)" : "(automatic)")
+            .append(", mRilVoiceRadioTechnology=").append(mRilVoiceRadioTechnology)
+            .append("(" + rilRadioTechnologyToString(mRilVoiceRadioTechnology) + ")")
+            .append(", mRilDataRadioTechnology=").append(mRilDataRadioTechnology)
+            .append("(" + rilRadioTechnologyToString(mRilDataRadioTechnology) + ")")
+            .append(", mCssIndicator=").append(mCssIndicator ? "supported" : "unsupported")
+            .append(", mNetworkId=").append(mNetworkId)
+            .append(", mSystemId=").append(mSystemId)
+            .append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator)
+            .append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator)
+            .append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
+            .append(", mIsDataRoamingFromRegistration=").append(mIsDataRoamingFromRegistration)
+            .append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
+            .append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
+            .append("}").toString();
     }
 
     private void setNullState(int state) {
diff --git a/core/tests/coretests/src/android/net/IpPrefixTest.java b/tests/net/java/android/net/IpPrefixTest.java
similarity index 93%
rename from core/tests/coretests/src/android/net/IpPrefixTest.java
rename to tests/net/java/android/net/IpPrefixTest.java
index 4f2387d..b5b2c07 100644
--- a/core/tests/coretests/src/android/net/IpPrefixTest.java
+++ b/tests/net/java/android/net/IpPrefixTest.java
@@ -16,18 +16,27 @@
 
 package android.net;
 
-import android.net.IpPrefix;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-import java.net.InetAddress;
-import java.util.Random;
-import junit.framework.TestCase;
-
-import static android.test.MoreAsserts.assertNotEqual;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
-public class IpPrefixTest extends TestCase {
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.net.InetAddress;
+import java.util.Random;
+
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IpPrefixTest {
 
     private static InetAddress Address(String addr) {
         return InetAddress.parseNumericAddress(addr);
@@ -42,7 +51,7 @@
         (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xa0
     };
 
-    @SmallTest
+    @Test
     public void testConstructor() {
         IpPrefix p;
         try {
@@ -103,6 +112,7 @@
         } catch(IllegalArgumentException expected) {}
     }
 
+    @Test
     public void testTruncation() {
         IpPrefix p;
 
@@ -170,7 +180,7 @@
         assertFalse(o2.equals(o1));
     }
 
-    @SmallTest
+    @Test
     public void testEquals() {
         IpPrefix p1, p2;
 
@@ -212,7 +222,7 @@
         assertAreNotEqual(p1, p2);
     }
 
-    @SmallTest
+    @Test
     public void testContains() {
         IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
         assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
@@ -240,7 +250,7 @@
         assertFalse(ipv4Default.contains(Address("2001:db8::f00")));
     }
 
-    @SmallTest
+    @Test
     public void testHashCode() {
         IpPrefix p = new IpPrefix(new byte[4], 0);
         Random random = new Random();
@@ -261,12 +271,12 @@
               assertEquals(p.hashCode(), oldP.hashCode());
             }
             if (p.hashCode() != oldP.hashCode()) {
-              assertNotEqual(p, oldP);
+              assertNotEquals(p, oldP);
             }
         }
     }
 
-    @SmallTest
+    @Test
     public void testHashCodeIsNotConstant() {
         IpPrefix[] prefixes = {
             new IpPrefix("2001:db8:f00::ace:d00d/127"),
@@ -276,12 +286,12 @@
         };
         for (int i = 0; i < prefixes.length; i++) {
           for (int j = i + 1; j < prefixes.length; j++) {
-            assertNotEqual(prefixes[i].hashCode(), prefixes[j].hashCode());
+            assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
           }
         }
     }
 
-    @SmallTest
+    @Test
     public void testMappedAddressesAreBroken() {
         // 192.0.2.0/24 != ::ffff:c000:0204/120, but because we use InetAddress,
         // we are unable to comprehend that.
@@ -318,13 +328,16 @@
       assertEquals(p, p2);
     }
 
+    @Test
     public void testParceling() {
         IpPrefix p;
 
         p = new IpPrefix("2001:4860:db8::/64");
         assertParcelingIsLossless(p);
+        assertTrue(p.isIPv6());
 
         p = new IpPrefix("192.0.2.0/25");
         assertParcelingIsLossless(p);
+        assertTrue(p.isIPv4());
     }
 }
diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/tests/net/java/android/net/LinkAddressTest.java
similarity index 91%
rename from core/tests/coretests/src/android/net/LinkAddressTest.java
rename to tests/net/java/android/net/LinkAddressTest.java
index adf8d95..c1ad946 100644
--- a/core/tests/coretests/src/android/net/LinkAddressTest.java
+++ b/tests/net/java/android/net/LinkAddressTest.java
@@ -16,6 +16,23 @@
 
 package android.net;
 
+import static android.system.OsConstants.IFA_F_DADFAILED;
+import static android.system.OsConstants.IFA_F_DEPRECATED;
+import static android.system.OsConstants.IFA_F_OPTIMISTIC;
+import static android.system.OsConstants.IFA_F_PERMANENT;
+import static android.system.OsConstants.IFA_F_TEMPORARY;
+import static android.system.OsConstants.IFA_F_TENTATIVE;
+import static android.system.OsConstants.RT_SCOPE_HOST;
+import static android.system.OsConstants.RT_SCOPE_LINK;
+import static android.system.OsConstants.RT_SCOPE_SITE;
+import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
 import java.net.Inet4Address;
 import java.net.Inet6Address;
 import java.net.InetAddress;
@@ -27,44 +44,35 @@
 import java.util.Comparator;
 import java.util.List;
 
-import android.net.LinkAddress;
 import android.os.Parcel;
-import android.test.AndroidTestCase;
-import static android.test.MoreAsserts.assertNotEqual;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
-import static android.system.OsConstants.IFA_F_DADFAILED;
-import static android.system.OsConstants.IFA_F_DEPRECATED;
-import static android.system.OsConstants.IFA_F_OPTIMISTIC;
-import static android.system.OsConstants.IFA_F_PERMANENT;
-import static android.system.OsConstants.IFA_F_TEMPORARY;
-import static android.system.OsConstants.IFA_F_TENTATIVE;
-import static android.system.OsConstants.RT_SCOPE_HOST;
-import static android.system.OsConstants.RT_SCOPE_LINK;
-import static android.system.OsConstants.RT_SCOPE_SITE;
-import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
+import org.junit.runner.RunWith;
+import org.junit.Test;
 
-/**
- * Tests for {@link LinkAddress}.
- */
-public class LinkAddressTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LinkAddressTest {
 
     private static final String V4 = "192.0.2.1";
     private static final String V6 = "2001:db8::1";
     private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4);
     private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6);
 
+    @Test
     public void testConstants() {
         // RT_SCOPE_UNIVERSE = 0, but all the other constants should be nonzero.
-        assertNotEqual(0, RT_SCOPE_HOST);
-        assertNotEqual(0, RT_SCOPE_LINK);
-        assertNotEqual(0, RT_SCOPE_SITE);
+        assertNotEquals(0, RT_SCOPE_HOST);
+        assertNotEquals(0, RT_SCOPE_LINK);
+        assertNotEquals(0, RT_SCOPE_SITE);
 
-        assertNotEqual(0, IFA_F_DEPRECATED);
-        assertNotEqual(0, IFA_F_PERMANENT);
-        assertNotEqual(0, IFA_F_TENTATIVE);
+        assertNotEquals(0, IFA_F_DEPRECATED);
+        assertNotEquals(0, IFA_F_PERMANENT);
+        assertNotEquals(0, IFA_F_TENTATIVE);
     }
 
+    @Test
     public void testConstructors() throws SocketException {
         LinkAddress address;
 
@@ -74,12 +82,14 @@
         assertEquals(25, address.getPrefixLength());
         assertEquals(0, address.getFlags());
         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
+        assertTrue(address.isIPv4());
 
         address = new LinkAddress(V6_ADDRESS, 127);
         assertEquals(V6_ADDRESS, address.getAddress());
         assertEquals(127, address.getPrefixLength());
         assertEquals(0, address.getFlags());
         assertEquals(RT_SCOPE_UNIVERSE, address.getScope());
+        assertTrue(address.isIPv6());
 
         // Nonsensical flags/scopes or combinations thereof are acceptable.
         address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK);
@@ -87,12 +97,14 @@
         assertEquals(64, address.getPrefixLength());
         assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags());
         assertEquals(RT_SCOPE_LINK, address.getScope());
+        assertTrue(address.isIPv6());
 
         address = new LinkAddress(V4 + "/23", 123, 456);
         assertEquals(V4_ADDRESS, address.getAddress());
         assertEquals(23, address.getPrefixLength());
         assertEquals(123, address.getFlags());
         assertEquals(456, address.getScope());
+        assertTrue(address.isIPv4());
 
         // InterfaceAddress doesn't have a constructor. Fetch some from an interface.
         List<InterfaceAddress> addrs = NetworkInterface.getByName("lo").getInterfaceAddresses();
@@ -174,6 +186,7 @@
         } catch(IllegalArgumentException expected) {}
     }
 
+    @Test
     public void testAddressScopes() {
         assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope());
         assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope());
@@ -216,6 +229,7 @@
         assertFalse(l2 + " unexpectedly equal to " + l1, l2.equals(l1));
     }
 
+    @Test
     public void testEqualsAndSameAddressAs() {
         LinkAddress l1, l2, l3;
 
@@ -293,26 +307,17 @@
         assertIsSameAddressAs(l1, l2);
     }
 
+    @Test
     public void testHashCode() {
-        LinkAddress l;
+        LinkAddress l1, l2;
 
-        l = new LinkAddress(V4_ADDRESS, 23);
-        assertEquals(-982787, l.hashCode());
+        l1 = new LinkAddress(V4_ADDRESS, 23);
+        l2 = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
+        assertNotEquals(l1.hashCode(), l2.hashCode());
 
-        l = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST);
-        assertEquals(-971865, l.hashCode());
-
-        l = new LinkAddress(V4_ADDRESS, 27);
-        assertEquals(-982743, l.hashCode());
-
-        l = new LinkAddress(V6_ADDRESS, 64);
-        assertEquals(1076522926, l.hashCode());
-
-        l = new LinkAddress(V6_ADDRESS, 128);
-        assertEquals(1076523630, l.hashCode());
-
-        l = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
-        assertEquals(1076524846, l.hashCode());
+        l1 = new LinkAddress(V6_ADDRESS, 128);
+        l2 = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE);
+        assertNotEquals(l1.hashCode(), l2.hashCode());
     }
 
     private LinkAddress passThroughParcel(LinkAddress l) {
@@ -334,6 +339,7 @@
       assertEquals(l, l2);
     }
 
+    @Test
     public void testParceling() {
         LinkAddress l;
 
@@ -352,6 +358,7 @@
         assertFalse(msg, l.isGlobalPreferred());
     }
 
+    @Test
     public void testIsGlobalPreferred() {
         LinkAddress l;
 
diff --git a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
index 45525e6..d29a94b 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/OffloadControllerTest.java
@@ -25,6 +25,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
@@ -45,6 +46,7 @@
 import android.net.NetworkStats;
 import android.net.RouteInfo;
 import android.net.util.SharedLog;
+import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.INetworkManagementService;
@@ -112,6 +114,12 @@
         Settings.Global.putInt(mContentResolver, TETHER_OFFLOAD_DISABLED, 0);
     }
 
+    private void waitForIdle() {
+        ConditionVariable cv = new ConditionVariable();
+        new Handler(Looper.getMainLooper()).post(() -> { cv.open(); });
+        cv.block();
+    }
+
     private OffloadController makeOffloadController() throws Exception {
         OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()),
                 mHardware, mContentResolver, mNMService, new SharedLog("test"));
@@ -421,4 +429,68 @@
         entry = stats.getValues(ethernetPosition, entry);
         assertNetworkStats(ethernetIface, ethernetStats, entry);
     }
+
+    @Test
+    public void testSetInterfaceQuota() throws Exception {
+        setupFunctioningHardwareInterface();
+        enableOffload();
+
+        final OffloadController offload = makeOffloadController();
+        offload.start();
+
+        final String ethernetIface = "eth1";
+        final String mobileIface = "rmnet_data0";
+        final long ethernetLimit = 12345;
+        final long mobileLimit = 12345678;
+
+        final LinkProperties lp = new LinkProperties();
+        lp.setInterfaceName(ethernetIface);
+        offload.setUpstreamLinkProperties(lp);
+
+        ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue();
+        final InOrder inOrder = inOrder(mHardware);
+        when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true);
+        when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true);
+
+        // Applying an interface quota to the current upstream immediately sends it to the hardware.
+        provider.setInterfaceQuota(ethernetIface, ethernetLimit);
+        waitForIdle();
+        inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit);
+        inOrder.verifyNoMoreInteractions();
+
+        // Applying an interface quota to another upstream does not take any immediate action.
+        provider.setInterfaceQuota(mobileIface, mobileLimit);
+        waitForIdle();
+        inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong());
+
+        // Switching to that upstream causes the quota to be applied if the parameters were applied
+        // correctly.
+        lp.setInterfaceName(mobileIface);
+        offload.setUpstreamLinkProperties(lp);
+        waitForIdle();
+        inOrder.verify(mHardware).setDataLimit(mobileIface, mobileLimit);
+
+        // Setting a limit of ITetheringStatsProvider.QUOTA_UNLIMITED causes the limit to be set
+        // to Long.MAX_VALUE.
+        provider.setInterfaceQuota(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED);
+        waitForIdle();
+        inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE);
+
+        // If setting upstream parameters fails, then the data limit is not set.
+        when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false);
+        lp.setInterfaceName(ethernetIface);
+        offload.setUpstreamLinkProperties(lp);
+        provider.setInterfaceQuota(mobileIface, mobileLimit);
+        waitForIdle();
+        inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong());
+
+        // If setting the data limit fails while changing upstreams, offload is stopped.
+        when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true);
+        when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false);
+        lp.setInterfaceName(mobileIface);
+        offload.setUpstreamLinkProperties(lp);
+        provider.setInterfaceQuota(mobileIface, mobileLimit);
+        waitForIdle();
+        inOrder.verify(mHardware).stopOffloadControl();
+    }
 }