Merge "Wait for unknown vis to resolve before forcing keyguard orientation" into pi-dev
diff --git a/api/current.txt b/api/current.txt
index c351bee..54f7d0f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6749,6 +6749,12 @@
     field public static final android.os.Parcelable.Creator<android.app.admin.DnsEvent> CREATOR;
   }
 
+  public class FreezePeriod {
+    ctor public FreezePeriod(java.time.MonthDay, java.time.MonthDay);
+    method public java.time.MonthDay getEnd();
+    method public java.time.MonthDay getStart();
+  }
+
   public abstract class NetworkEvent implements android.os.Parcelable {
     method public int describeContents();
     method public long getId();
@@ -6819,16 +6825,16 @@
     field public static final int SECURITY_PATCH_STATE_UNKNOWN = 0; // 0x0
   }
 
-  public class SystemUpdatePolicy implements android.os.Parcelable {
+  public final class SystemUpdatePolicy implements android.os.Parcelable {
     method public static android.app.admin.SystemUpdatePolicy createAutomaticInstallPolicy();
     method public static android.app.admin.SystemUpdatePolicy createPostponeInstallPolicy();
     method public static android.app.admin.SystemUpdatePolicy createWindowedInstallPolicy(int, int);
     method public int describeContents();
-    method public java.util.List<android.util.Pair<java.lang.Integer, java.lang.Integer>> getFreezePeriods();
+    method public java.util.List<android.app.admin.FreezePeriod> getFreezePeriods();
     method public int getInstallWindowEnd();
     method public int getInstallWindowStart();
     method public int getPolicyType();
-    method public android.app.admin.SystemUpdatePolicy setFreezePeriods(java.util.List<android.util.Pair<java.lang.Integer, java.lang.Integer>>);
+    method public android.app.admin.SystemUpdatePolicy setFreezePeriods(java.util.List<android.app.admin.FreezePeriod>);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.admin.SystemUpdatePolicy> CREATOR;
     field public static final int TYPE_INSTALL_AUTOMATIC = 1; // 0x1
@@ -6841,11 +6847,12 @@
     method public int getErrorCode();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.admin.SystemUpdatePolicy.ValidationFailedException> CREATOR;
-    field public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE = 5; // 0x5
-    field public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG = 4; // 0x4
-    field public static final int ERROR_DUPLICATE_OR_OVERLAP = 1; // 0x1
-    field public static final int ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE = 3; // 0x3
-    field public static final int ERROR_NEW_FREEZE_PERIOD_TOO_LONG = 2; // 0x2
+    field public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE = 6; // 0x6
+    field public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG = 5; // 0x5
+    field public static final int ERROR_DUPLICATE_OR_OVERLAP = 2; // 0x2
+    field public static final int ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE = 4; // 0x4
+    field public static final int ERROR_NEW_FREEZE_PERIOD_TOO_LONG = 3; // 0x3
+    field public static final int ERROR_UNKNOWN = 1; // 0x1
   }
 
 }
@@ -51320,7 +51327,6 @@
     method public android.graphics.Bitmap getFavicon();
     method public android.webkit.WebView.HitTestResult getHitTestResult();
     method public deprecated java.lang.String[] getHttpAuthUsernamePassword(java.lang.String, java.lang.String);
-    method public android.os.Looper getLooper();
     method public java.lang.String getOriginalUrl();
     method public int getProgress();
     method public boolean getRendererPriorityWaivedWhenNotVisible();
diff --git a/api/system-current.txt b/api/system-current.txt
index 4260e40..7e95ddc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -452,7 +452,7 @@
     field public static final int STATE_USER_UNMANAGED = 0; // 0x0
   }
 
-  public class SystemUpdatePolicy implements android.os.Parcelable {
+  public final class SystemUpdatePolicy implements android.os.Parcelable {
     method public int describeContents();
     method public android.app.admin.SystemUpdatePolicy.InstallationOption getInstallationOptionAt(long);
     method public void writeToParcel(android.os.Parcel, int);
@@ -4355,6 +4355,7 @@
     method public byte[] getServerParams();
     method public int getSnapshotVersion();
     method public java.security.cert.CertPath getTrustedHardwareCertPath();
+    method public deprecated byte[] getTrustedHardwarePublicKey();
     method public java.util.List<android.security.keystore.recovery.WrappedApplicationKey> getWrappedApplicationKeys();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.security.keystore.recovery.KeyChainSnapshot> CREATOR;
@@ -4379,18 +4380,25 @@
 
   public class RecoveryController {
     method public android.security.keystore.recovery.RecoverySession createRecoverySession();
+    method public byte[] generateAndStoreKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method public deprecated java.security.Key generateKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
     method public java.security.Key generateKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method public deprecated java.util.List<java.lang.String> getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public java.util.List<java.lang.String> getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public static android.security.keystore.recovery.RecoveryController getInstance(android.content.Context);
     method public java.security.Key getKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException, java.security.UnrecoverableKeyException;
     method public android.security.keystore.recovery.KeyChainSnapshot getKeyChainSnapshot() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public deprecated android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public int getRecoveryStatus(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public java.util.Map<java.lang.String, java.security.cert.X509Certificate> getRootCertificates();
     method public java.security.Key importKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
+    method public deprecated void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
     method public void initRecoveryService(java.lang.String, byte[], byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
     method public void removeKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public void setRecoverySecretTypes(int[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public deprecated void setRecoveryStatus(java.lang.String, java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.content.pm.PackageManager.NameNotFoundException;
     method public void setRecoveryStatus(java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public void setServerParams(byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException;
     method public void setSnapshotCreatedPendingIntent(android.app.PendingIntent) throws android.security.keystore.recovery.InternalRecoveryServiceException;
@@ -4402,6 +4410,9 @@
   public class RecoverySession implements java.lang.AutoCloseable {
     method public void close();
     method public java.util.Map<java.lang.String, java.security.Key> recoverKeyChainSnapshot(byte[], java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
+    method public deprecated java.util.Map<java.lang.String, byte[]> recoverKeys(byte[], java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
+    method public deprecated byte[] start(byte[], byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
+    method public deprecated byte[] start(java.security.cert.CertPath, byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
     method public byte[] start(java.lang.String, java.security.cert.CertPath, byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
   }
 
@@ -4411,6 +4422,7 @@
 
   public final class WrappedApplicationKey implements android.os.Parcelable {
     method public int describeContents();
+    method public deprecated byte[] getAccount();
     method public java.lang.String getAlias();
     method public byte[] getEncryptedKeyMaterial();
     method public void writeToParcel(android.os.Parcel, int);
@@ -4420,6 +4432,7 @@
   public static class WrappedApplicationKey.Builder {
     ctor public WrappedApplicationKey.Builder();
     method public android.security.keystore.recovery.WrappedApplicationKey build();
+    method public deprecated android.security.keystore.recovery.WrappedApplicationKey.Builder setAccount(byte[]);
     method public android.security.keystore.recovery.WrappedApplicationKey.Builder setAlias(java.lang.String);
     method public android.security.keystore.recovery.WrappedApplicationKey.Builder setEncryptedKeyMaterial(byte[]);
   }
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 7cf12ef..48f43e0 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -91,37 +91,6 @@
 
 }
 
-package android.security.keystore.recovery {
-
-  public final class KeyChainSnapshot implements android.os.Parcelable {
-    method public deprecated byte[] getTrustedHardwarePublicKey();
-  }
-
-  public class RecoveryController {
-    method public deprecated java.security.Key generateKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
-    method public deprecated java.util.List<java.lang.String> getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public deprecated android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public deprecated void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public deprecated void setRecoveryStatus(java.lang.String, java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.content.pm.PackageManager.NameNotFoundException;
-  }
-
-  public class RecoverySession implements java.lang.AutoCloseable {
-    method public deprecated java.util.Map<java.lang.String, byte[]> recoverKeys(byte[], java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
-    method public deprecated byte[] start(byte[], byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
-    method public deprecated byte[] start(java.security.cert.CertPath, byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
-  }
-
-  public final class WrappedApplicationKey implements android.os.Parcelable {
-    method public deprecated byte[] getAccount();
-  }
-
-  public static class WrappedApplicationKey.Builder {
-    method public deprecated android.security.keystore.recovery.WrappedApplicationKey.Builder setAccount(byte[]);
-  }
-
-}
-
 package android.service.notification {
 
   public abstract class NotificationListenerService extends android.app.Service {
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 205d498..e00ce85 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -1225,11 +1225,11 @@
 Landroid/net/wifi/p2p/WifiP2pGroup;->TEMPORARY_NET_ID:I
 Landroid/net/wifi/p2p/WifiP2pManager$Channel;->mAsyncChannel:Lcom/android/internal/util/AsyncChannel;
 Landroid/net/wifi/p2p/WifiP2pManager$Channel;->putListener(Ljava/lang/Object;)I
+Landroid/net/wifi/p2p/WifiP2pManager;->CREATE_GROUP:I
 Landroid/net/wifi/p2p/WifiP2pManager;->deletePersistentGroup(Landroid/net/wifi/p2p/WifiP2pManager$Channel;ILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
 Landroid/net/wifi/p2p/WifiP2pManager;->requestPersistentGroupInfo(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Landroid/net/wifi/p2p/WifiP2pManager$PersistentGroupInfoListener;)V
 Landroid/net/wifi/p2p/WifiP2pManager;->setDeviceName(Landroid/net/wifi/p2p/WifiP2pManager$Channel;Ljava/lang/String;Landroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
 Landroid/net/wifi/p2p/WifiP2pManager;->setWifiP2pChannels(Landroid/net/wifi/p2p/WifiP2pManager$Channel;IILandroid/net/wifi/p2p/WifiP2pManager$ActionListener;)V
-Landroid/net/wifi/p2p/WifiP2pManager;->CREATE_GROUP:I
 Landroid/net/wifi/ScanResult;->anqpDomainId:I
 Landroid/net/wifi/ScanResult;->anqpLines:Ljava/util/List;
 Landroid/net/wifi/ScanResult;->distanceCm:I
@@ -1598,6 +1598,7 @@
 Landroid/provider/Browser;->clearSearches(Landroid/content/ContentResolver;)V
 Landroid/provider/Browser;->deleteFromHistory(Landroid/content/ContentResolver;Ljava/lang/String;)V
 Landroid/provider/Browser;->getVisitedHistory(Landroid/content/ContentResolver;)[Ljava/lang/String;
+Landroid/provider/Browser;->HISTORY_PROJECTION:[Ljava/lang/String;
 Landroid/provider/Browser;->SEARCHES_URI:Landroid/net/Uri;
 Landroid/provider/Browser;->sendString(Landroid/content/Context;Ljava/lang/String;Ljava/lang/String;)V
 Landroid/provider/Browser;->updateVisitedHistory(Landroid/content/ContentResolver;Ljava/lang/String;Z)V
@@ -3008,6 +3009,8 @@
 Lcom/android/internal/telephony/ITelephony;->getCallState()I
 Lcom/android/internal/telephony/ITelephony;->getDataState()I
 Lcom/android/internal/telephony/ITelephony;->isIdle(Ljava/lang/String;)Z
+Lcom/android/internal/telephony/ITelephonyRegistry;->notifyCallState(ILjava/lang/String;)V
+Lcom/android/internal/telephony/ITelephonyRegistry$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephonyRegistry;
 Lcom/android/internal/telephony/ITelephony;->silenceRinger()V
 Lcom/android/internal/telephony/ITelephony$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ITelephony;
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->endCall()Z
@@ -3192,6 +3195,7 @@
 Ljava/lang/Float;->value:F
 Ljava/lang/Integer;->value:I
 Ljava/lang/Long;->value:J
+Ljava/lang/invoke/MethodHandles$Lookup;-><init>(Ljava/lang/Class;I)V
 Ljava/lang/ref/FinalizerReference;->add(Ljava/lang/Object;)V
 Ljava/lang/ref/FinalizerReference;->head:Ljava/lang/ref/FinalizerReference;
 Ljava/lang/ref/FinalizerReference;->next:Ljava/lang/ref/FinalizerReference;
diff --git a/core/java/android/app/admin/FreezeInterval.java b/core/java/android/app/admin/FreezePeriod.java
similarity index 74%
rename from core/java/android/app/admin/FreezeInterval.java
rename to core/java/android/app/admin/FreezePeriod.java
index de5e21a..657f017 100644
--- a/core/java/android/app/admin/FreezeInterval.java
+++ b/core/java/android/app/admin/FreezePeriod.java
@@ -20,49 +20,88 @@
 import android.util.Pair;
 
 import java.time.LocalDate;
+import java.time.MonthDay;
 import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.List;
 
 /**
- * An interval representing one freeze period which repeats annually. We use the number of days
- * since the start of (non-leap) year to define the start and end dates of an interval, both
- * inclusive. If the end date is smaller than the start date, the interval is considered wrapped
- * around the year-end. As far as an interval is concerned, February 29th should be treated as
- * if it were February 28th: so an interval starting or ending on February 28th are not
- * distinguishable from an interval on February 29th. When calulating interval length or
- * distance between two dates, February 29th is also disregarded.
+ * A class that represents one freeze period which repeats <em>annually</em>. A freeze period has
+ * two {@link java.time#MonthDay} values that define the start and end dates of the period, both
+ * inclusive. If the end date is earlier than the start date, the period is considered wrapped
+ * around the year-end. As far as freeze period is concerned, leap year is disregarded and February
+ * 29th should be treated as if it were February 28th: so a freeze starting or ending on February
+ * 28th is identical to a freeze starting or ending on February 29th. When calulating the length of
+ * a freeze or the distance bewteen two freee periods, February 29th is also ignored.
  *
  * @see SystemUpdatePolicy#setFreezePeriods
- * @hide
  */
-public class FreezeInterval {
-    private static final String TAG = "FreezeInterval";
+public class FreezePeriod {
+    private static final String TAG = "FreezePeriod";
 
     private static final int DUMMY_YEAR = 2001;
     static final int DAYS_IN_YEAR = 365; // 365 since DUMMY_YEAR is not a leap year
 
-    final int mStartDay; // [1,365]
-    final int mEndDay; // [1,365]
+    private final MonthDay mStart;
+    private final MonthDay mEnd;
 
-    FreezeInterval(int startDay, int endDay) {
-        if (startDay < 1 || startDay > 365 || endDay < 1 || endDay > 365) {
-            throw new RuntimeException("Bad dates for Interval: " + startDay + "," + endDay);
-        }
-        mStartDay = startDay;
-        mEndDay = endDay;
+    /*
+     * Start and end dates represented by number of days since the beginning of the year.
+     * They are internal representations of mStart and mEnd with normalized Leap year days
+     * (Feb 29 == Feb 28 == 59th day of year). All internal calclations are based on
+     * these two values so that leap year days are disregarded.
+     */
+    private final int mStartDay; // [1, 365]
+    private final int mEndDay; // [1, 365]
+
+    /**
+     * Creates a freeze period by its start and end dates. If the end date is earlier than the start
+     * date, the freeze period is considered wrapping year-end.
+     */
+    public FreezePeriod(MonthDay start, MonthDay end) {
+        mStart = start;
+        mStartDay = mStart.atYear(DUMMY_YEAR).getDayOfYear();
+        mEnd = end;
+        mEndDay = mEnd.atYear(DUMMY_YEAR).getDayOfYear();
     }
 
+    /**
+     * Returns the start date (inclusive) of this freeze period.
+     */
+    public MonthDay getStart() {
+        return mStart;
+    }
+
+    /**
+     * Returns the end date (inclusive) of this freeze period.
+     */
+    public MonthDay getEnd() {
+        return mEnd;
+    }
+
+    /**
+     * @hide
+     */
+    private FreezePeriod(int startDay, int endDay) {
+        mStartDay = startDay;
+        mStart = dayOfYearToMonthDay(startDay);
+        mEndDay = endDay;
+        mEnd = dayOfYearToMonthDay(endDay);
+    }
+
+    /** @hide */
     int getLength() {
         return getEffectiveEndDay() - mStartDay + 1;
     }
 
+    /** @hide */
     boolean isWrapped() {
         return mEndDay < mStartDay;
     }
 
     /**
      * Returns the effective end day, taking wrapping around year-end into consideration
+     * @hide
      */
     int getEffectiveEndDay() {
         if (!isWrapped()) {
@@ -72,6 +111,7 @@
         }
     }
 
+    /** @hide */
     boolean contains(LocalDate localDate) {
         final int daysOfYear = dayOfYearDisregardLeapYear(localDate);
         if (!isWrapped()) {
@@ -84,6 +124,7 @@
         }
     }
 
+    /** @hide */
     boolean after(LocalDate localDate) {
         return mStartDay > dayOfYearDisregardLeapYear(localDate);
     }
@@ -95,6 +136,7 @@
      * include now, the returned dates represents the next future interval.
      * The result will always have the same month and dayOfMonth value as the non-instantiated
      * interval itself.
+     * @hide
      */
     Pair<LocalDate, LocalDate> toCurrentOrFutureRealDates(LocalDate now) {
         final int nowDays = dayOfYearDisregardLeapYear(now);
@@ -138,14 +180,24 @@
                 + LocalDate.ofYearDay(DUMMY_YEAR, mEndDay).format(formatter);
     }
 
-    // Treat the supplied date as in a non-leap year and return its day of year.
-    static int dayOfYearDisregardLeapYear(LocalDate date) {
+    /** @hide */
+    private static MonthDay dayOfYearToMonthDay(int dayOfYear) {
+        LocalDate date = LocalDate.ofYearDay(DUMMY_YEAR, dayOfYear);
+        return MonthDay.of(date.getMonth(), date.getDayOfMonth());
+    }
+
+    /**
+     * Treat the supplied date as in a non-leap year and return its day of year.
+     * @hide
+     */
+    private static int dayOfYearDisregardLeapYear(LocalDate date) {
         return date.withYear(DUMMY_YEAR).getDayOfYear();
     }
 
     /**
      * Compute the number of days between first (inclusive) and second (exclusive),
      * treating all years in between as non-leap.
+     * @hide
      */
     public static int distanceWithoutLeapYear(LocalDate first, LocalDate second) {
         return dayOfYearDisregardLeapYear(first) - dayOfYearDisregardLeapYear(second)
@@ -165,16 +217,16 @@
      *     3. At most one wrapped Interval remains, and it will be at the end of the list
      * @hide
      */
-    protected static List<FreezeInterval> canonicalizeIntervals(List<FreezeInterval> intervals) {
+    static List<FreezePeriod> canonicalizePeriods(List<FreezePeriod> intervals) {
         boolean[] taken = new boolean[DAYS_IN_YEAR];
         // First convert the intervals into flat array
-        for (FreezeInterval interval : intervals) {
+        for (FreezePeriod interval : intervals) {
             for (int i = interval.mStartDay; i <= interval.getEffectiveEndDay(); i++) {
                 taken[(i - 1) % DAYS_IN_YEAR] = true;
             }
         }
         // Then reconstruct intervals from the array
-        List<FreezeInterval> result = new ArrayList<>();
+        List<FreezePeriod> result = new ArrayList<>();
         int i = 0;
         while (i < DAYS_IN_YEAR) {
             if (!taken[i]) {
@@ -183,14 +235,14 @@
             }
             final int intervalStart = i + 1;
             while (i < DAYS_IN_YEAR && taken[i]) i++;
-            result.add(new FreezeInterval(intervalStart, i));
+            result.add(new FreezePeriod(intervalStart, i));
         }
         // Check if the last entry can be merged to the first entry to become one single
         // wrapped interval
         final int lastIndex = result.size() - 1;
         if (lastIndex > 0 && result.get(lastIndex).mEndDay == DAYS_IN_YEAR
                 && result.get(0).mStartDay == 1) {
-            FreezeInterval wrappedInterval = new FreezeInterval(result.get(lastIndex).mStartDay,
+            FreezePeriod wrappedInterval = new FreezePeriod(result.get(lastIndex).mStartDay,
                     result.get(0).mEndDay);
             result.set(lastIndex, wrappedInterval);
             result.remove(0);
@@ -207,18 +259,18 @@
      *
      * @hide
      */
-    protected static void validatePeriods(List<FreezeInterval> periods) {
-        List<FreezeInterval> allPeriods = FreezeInterval.canonicalizeIntervals(periods);
+    static void validatePeriods(List<FreezePeriod> periods) {
+        List<FreezePeriod> allPeriods = FreezePeriod.canonicalizePeriods(periods);
         if (allPeriods.size() != periods.size()) {
             throw SystemUpdatePolicy.ValidationFailedException.duplicateOrOverlapPeriods();
         }
         for (int i = 0; i < allPeriods.size(); i++) {
-            FreezeInterval current = allPeriods.get(i);
+            FreezePeriod current = allPeriods.get(i);
             if (current.getLength() > SystemUpdatePolicy.FREEZE_PERIOD_MAX_LENGTH) {
                 throw SystemUpdatePolicy.ValidationFailedException.freezePeriodTooLong("Freeze "
                         + "period " + current + " is too long: " + current.getLength() + " days");
             }
-            FreezeInterval previous = i > 0 ? allPeriods.get(i - 1)
+            FreezePeriod previous = i > 0 ? allPeriods.get(i - 1)
                     : allPeriods.get(allPeriods.size() - 1);
             if (previous != current) {
                 final int separation;
@@ -247,7 +299,7 @@
      *
      * @hide
      */
-    protected static void validateAgainstPreviousFreezePeriod(List<FreezeInterval> periods,
+    static void validateAgainstPreviousFreezePeriod(List<FreezePeriod> periods,
             LocalDate prevPeriodStart, LocalDate prevPeriodEnd, LocalDate now) {
         if (periods.size() == 0 || prevPeriodStart == null || prevPeriodEnd == null) {
             return;
@@ -258,14 +310,14 @@
             // Clock was adjusted backwards. We can continue execution though, the separation
             // and length validation below still works under this condition.
         }
-        List<FreezeInterval> allPeriods = FreezeInterval.canonicalizeIntervals(periods);
+        List<FreezePeriod> allPeriods = FreezePeriod.canonicalizePeriods(periods);
         // Given current time now, find the freeze period that's either current, or the one
         // that's immediately afterwards. For the later case, it might be after the year-end,
         // but this can only happen if there is only one freeze period.
-        FreezeInterval curOrNextFreezePeriod = allPeriods.get(0);
-        for (FreezeInterval interval : allPeriods) {
+        FreezePeriod curOrNextFreezePeriod = allPeriods.get(0);
+        for (FreezePeriod interval : allPeriods) {
             if (interval.contains(now)
-                    || interval.mStartDay > FreezeInterval.dayOfYearDisregardLeapYear(now)) {
+                    || interval.mStartDay > FreezePeriod.dayOfYearDisregardLeapYear(now)) {
                 curOrNextFreezePeriod = interval;
                 break;
             }
@@ -282,7 +334,7 @@
         // Now validate [prevPeriodStart, prevPeriodEnd] against curOrNextFreezeDates
         final String periodsDescription = "Prev: " + prevPeriodStart + "," + prevPeriodEnd
                 + "; cur: " + curOrNextFreezeDates.first + "," + curOrNextFreezeDates.second;
-        long separation = FreezeInterval.distanceWithoutLeapYear(curOrNextFreezeDates.first,
+        long separation = FreezePeriod.distanceWithoutLeapYear(curOrNextFreezeDates.first,
                 prevPeriodEnd) - 1;
         if (separation > 0) {
             // Two intervals do not overlap, check separation
@@ -292,7 +344,7 @@
             }
         } else {
             // Two intervals overlap, check combined length
-            long length = FreezeInterval.distanceWithoutLeapYear(curOrNextFreezeDates.second,
+            long length = FreezePeriod.distanceWithoutLeapYear(curOrNextFreezeDates.second,
                     prevPeriodStart) + 1;
             if (length > SystemUpdatePolicy.FREEZE_PERIOD_MAX_LENGTH) {
                 throw ValidationFailedException.combinedPeriodTooLong("Combined freeze period "
diff --git a/core/java/android/app/admin/SystemUpdatePolicy.java b/core/java/android/app/admin/SystemUpdatePolicy.java
index 47b3a81..20eef6c 100644
--- a/core/java/android/app/admin/SystemUpdatePolicy.java
+++ b/core/java/android/app/admin/SystemUpdatePolicy.java
@@ -38,9 +38,11 @@
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
+import java.time.MonthDay;
 import java.time.ZoneId;
 import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -51,7 +53,7 @@
  * @see DevicePolicyManager#setSystemUpdatePolicy
  * @see DevicePolicyManager#getSystemUpdatePolicy
  */
-public class SystemUpdatePolicy implements Parcelable {
+public final class SystemUpdatePolicy implements Parcelable {
     private static final String TAG = "SystemUpdatePolicy";
 
     /** @hide */
@@ -163,6 +165,7 @@
                 ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE,
                 ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG,
                 ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE,
+                ERROR_UNKNOWN,
         })
         @Retention(RetentionPolicy.SOURCE)
         @interface ValidationFailureType {}
@@ -171,33 +174,38 @@
         public static final int ERROR_NONE = 0;
 
         /**
+         * Validation failed with unknown error.
+         */
+        public static final int ERROR_UNKNOWN = 1;
+
+        /**
          * The freeze periods contains duplicates, periods that overlap with each
          * other or periods whose start and end joins.
          */
-        public static final int ERROR_DUPLICATE_OR_OVERLAP = 1;
+        public static final int ERROR_DUPLICATE_OR_OVERLAP = 2;
 
         /**
          * There exists at least one freeze period whose length exceeds 90 days.
          */
-        public static final int ERROR_NEW_FREEZE_PERIOD_TOO_LONG = 2;
+        public static final int ERROR_NEW_FREEZE_PERIOD_TOO_LONG = 3;
 
         /**
          * There exists some freeze period which starts within 60 days of the preceding period's
          * end time.
          */
-        public static final int ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE = 3;
+        public static final int ERROR_NEW_FREEZE_PERIOD_TOO_CLOSE = 4;
 
         /**
          * The device has been in a freeze period and when combining with the new freeze period
          * to be set, it will result in the total freeze period being longer than 90 days.
          */
-        public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG = 4;
+        public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_LONG = 5;
 
         /**
          * The device has been in a freeze period and some new freeze period to be set is less
          * than 60 days from the end of the last freeze period the device went through.
          */
-        public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE = 5;
+        public static final int ERROR_COMBINED_FREEZE_PERIOD_TOO_CLOSE = 6;
 
         @ValidationFailureType
         private final int mErrorCode;
@@ -272,7 +280,7 @@
     private int mMaintenanceWindowStart;
     private int mMaintenanceWindowEnd;
 
-    private final ArrayList<FreezeInterval> mFreezePeriods;
+    private final ArrayList<FreezePeriod> mFreezePeriods;
 
     private SystemUpdatePolicy() {
         mPolicyType = TYPE_UNKNOWN;
@@ -444,12 +452,10 @@
      *         requirement set above
      * @return this instance
      */
-    public SystemUpdatePolicy setFreezePeriods(List<Pair<Integer, Integer>> freezePeriods) {
-        List<FreezeInterval> newPeriods = freezePeriods.stream().map(
-                p -> new FreezeInterval(p.first, p.second)).collect(Collectors.toList());
-        FreezeInterval.validatePeriods(newPeriods);
+    public SystemUpdatePolicy setFreezePeriods(List<FreezePeriod> freezePeriods) {
+        FreezePeriod.validatePeriods(freezePeriods);
         mFreezePeriods.clear();
-        mFreezePeriods.addAll(newPeriods);
+        mFreezePeriods.addAll(freezePeriods);
         return this;
     }
 
@@ -458,12 +464,8 @@
      *
      * @return the list of freeze periods, or an empty list if none was set.
      */
-    public List<Pair<Integer, Integer>> getFreezePeriods() {
-        List<Pair<Integer, Integer>> result = new ArrayList<>(mFreezePeriods.size());
-        for (FreezeInterval interval : mFreezePeriods) {
-            result.add(new Pair<>(interval.mStartDay, interval.mEndDay));
-        }
-        return result;
+    public List<FreezePeriod> getFreezePeriods() {
+        return Collections.unmodifiableList(mFreezePeriods);
     }
 
     /**
@@ -472,7 +474,7 @@
      * @hide
      */
     public Pair<LocalDate, LocalDate> getCurrentFreezePeriod(LocalDate now) {
-        for (FreezeInterval interval : mFreezePeriods) {
+        for (FreezePeriod interval : mFreezePeriods) {
             if (interval.contains(now)) {
                 return interval.toCurrentOrFutureRealDates(now);
             }
@@ -485,10 +487,10 @@
      * is not within a freeze period.
      */
     private long timeUntilNextFreezePeriod(long now) {
-        List<FreezeInterval> sortedPeriods = FreezeInterval.canonicalizeIntervals(mFreezePeriods);
+        List<FreezePeriod> sortedPeriods = FreezePeriod.canonicalizePeriods(mFreezePeriods);
         LocalDate nowDate = millisToDate(now);
         LocalDate nextFreezeStart = null;
-        for (FreezeInterval interval : sortedPeriods) {
+        for (FreezePeriod interval : sortedPeriods) {
             if (interval.after(nowDate)) {
                 nextFreezeStart = interval.toCurrentOrFutureRealDates(nowDate).first;
                 break;
@@ -506,13 +508,13 @@
 
     /** @hide */
     public void validateFreezePeriods() {
-        FreezeInterval.validatePeriods(mFreezePeriods);
+        FreezePeriod.validatePeriods(mFreezePeriods);
     }
 
     /** @hide */
     public void validateAgainstPreviousFreezePeriod(LocalDate prevPeriodStart,
             LocalDate prevPeriodEnd, LocalDate now) {
-        FreezeInterval.validateAgainstPreviousFreezePeriod(mFreezePeriods, prevPeriodStart,
+        FreezePeriod.validateAgainstPreviousFreezePeriod(mFreezePeriods, prevPeriodStart,
                 prevPeriodEnd, now);
     }
 
@@ -521,10 +523,10 @@
      * updates and how long this action is valid for, given the current system update policy. Its
      * action could be one of the following
      * <ul>
-     * <li> {@code TYPE_INSTALL_AUTOMATIC} system updates should be installed immedately and without
-     * user intervention as soon as they become available.
-     * <li> {@code TYPE_POSTPONE} system updates should be postponed for a maximum of 30 days
-     * <li> {@code TYPE_PAUSE} system updates should be postponed indefinitely until further notice
+     * <li> {@link #TYPE_INSTALL_AUTOMATIC} system updates should be installed immedately and
+     * without user intervention as soon as they become available.
+     * <li> {@link #TYPE_POSTPONE} system updates should be postponed for a maximum of 30 days
+     * <li> {@link #TYPE_PAUSE} system updates should be postponed indefinitely until further notice
      * </ul>
      *
      * The effective time measures how long this installation option is valid for from the queried
@@ -535,18 +537,38 @@
      */
     @SystemApi
     public static class InstallationOption {
+        /** @hide */
+        @IntDef(prefix = { "TYPE_" }, value = {
+                TYPE_INSTALL_AUTOMATIC,
+                TYPE_PAUSE,
+                TYPE_POSTPONE
+        })
+        @Retention(RetentionPolicy.SOURCE)
+        @interface InstallationOptionType {}
+
+        @InstallationOptionType
         private final int mType;
         private long mEffectiveTime;
 
-        InstallationOption(int type, long effectiveTime) {
+        InstallationOption(@InstallationOptionType int type, long effectiveTime) {
             this.mType = type;
             this.mEffectiveTime = effectiveTime;
         }
 
-        public int getType() {
+        /**
+         * Returns the type of the current installation option, could be one of
+         * {@link #TYPE_INSTALL_AUTOMATIC}, {@link #TYPE_POSTPONE} and {@link #TYPE_PAUSE}.
+         * @return type of installation option.
+         */
+        public @InstallationOptionType int getType() {
             return mType;
         }
 
+        /**
+         * Returns how long the current installation option in effective for, starting from the time
+         * of query.
+         * @return the effective time in milliseconds.
+         */
         public long getEffectiveTime() {
             return mEffectiveTime;
         }
@@ -667,9 +689,11 @@
         int freezeCount = mFreezePeriods.size();
         dest.writeInt(freezeCount);
         for (int i = 0; i < freezeCount; i++) {
-            FreezeInterval interval = mFreezePeriods.get(i);
-            dest.writeInt(interval.mStartDay);
-            dest.writeInt(interval.mEndDay);
+            FreezePeriod interval = mFreezePeriods.get(i);
+            dest.writeInt(interval.getStart().getMonthValue());
+            dest.writeInt(interval.getStart().getDayOfMonth());
+            dest.writeInt(interval.getEnd().getMonthValue());
+            dest.writeInt(interval.getEnd().getDayOfMonth());
         }
     }
 
@@ -686,8 +710,9 @@
                     int freezeCount = source.readInt();
                     policy.mFreezePeriods.ensureCapacity(freezeCount);
                     for (int i = 0; i < freezeCount; i++) {
-                        policy.mFreezePeriods.add(
-                                new FreezeInterval(source.readInt(), source.readInt()));
+                        MonthDay start = MonthDay.of(source.readInt(), source.readInt());
+                        MonthDay end = MonthDay.of(source.readInt(), source.readInt());
+                        policy.mFreezePeriods.add(new FreezePeriod(start, end));
                     }
                     return policy;
                 }
@@ -730,9 +755,9 @@
                     if (!parser.getName().equals(KEY_FREEZE_TAG)) {
                         continue;
                     }
-                    policy.mFreezePeriods.add(new FreezeInterval(
-                            Integer.parseInt(parser.getAttributeValue(null, KEY_FREEZE_START)),
-                            Integer.parseInt(parser.getAttributeValue(null, KEY_FREEZE_END))));
+                    policy.mFreezePeriods.add(new FreezePeriod(
+                            MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_START)),
+                            MonthDay.parse(parser.getAttributeValue(null, KEY_FREEZE_END))));
                 }
                 return policy;
             }
@@ -751,10 +776,10 @@
         out.attribute(null, KEY_INSTALL_WINDOW_START, Integer.toString(mMaintenanceWindowStart));
         out.attribute(null, KEY_INSTALL_WINDOW_END, Integer.toString(mMaintenanceWindowEnd));
         for (int i = 0; i < mFreezePeriods.size(); i++) {
-            FreezeInterval interval = mFreezePeriods.get(i);
+            FreezePeriod interval = mFreezePeriods.get(i);
             out.startTag(null, KEY_FREEZE_TAG);
-            out.attribute(null, KEY_FREEZE_START, Integer.toString(interval.mStartDay));
-            out.attribute(null, KEY_FREEZE_END, Integer.toString(interval.mEndDay));
+            out.attribute(null, KEY_FREEZE_START, interval.getStart().toString());
+            out.attribute(null, KEY_FREEZE_END, interval.getEnd().toString());
             out.endTag(null, KEY_FREEZE_TAG);
         }
     }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6748cdb..49b1efd 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1132,11 +1132,12 @@
      */
     public static final int HIDDEN_API_ENFORCEMENT_NONE = 0;
     /**
-     * Light grey list enforcement, the strictest option. Enforces the light grey, dark grey and
-     * black lists.
+     * No API enforcement, but enable the detection logic and warnings. Observed behaviour is the
+     * same as {@link #HIDDEN_API_ENFORCEMENT_NONE} but you may see warnings in the log when APIs
+     * are accessed.
      * @hide
      * */
-    public static final int HIDDEN_API_ENFORCEMENT_ALL_LISTS = 1;
+    public static final int HIDDEN_API_ENFORCEMENT_JUST_WARN = 1;
     /**
      * Dark grey list enforcement. Enforces the dark grey and black lists
      * @hide
@@ -1158,7 +1159,7 @@
     @IntDef(prefix = { "HIDDEN_API_ENFORCEMENT_" }, value = {
             HIDDEN_API_ENFORCEMENT_DEFAULT,
             HIDDEN_API_ENFORCEMENT_NONE,
-            HIDDEN_API_ENFORCEMENT_ALL_LISTS,
+            HIDDEN_API_ENFORCEMENT_JUST_WARN,
             HIDDEN_API_ENFORCEMENT_DARK_GREY_AND_BLACK,
             HIDDEN_API_ENFORCEMENT_BLACK,
     })
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index b9dd376..d1d5d8e 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -467,7 +467,8 @@
      * <p>The list of exemptions will take affect for all new processes forked from the zygote after
      * this call.
      *
-     * @param exemptions List of hidden API exemption prefixes.
+     * @param exemptions List of hidden API exemption prefixes. Any matching members are treated as
+     *        whitelisted/public APIs (i.e. allowed, no logging of usage).
      */
     public void setApiBlacklistExemptions(List<String> exemptions) {
         synchronized (mLock) {
diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
index 73a6a74..9334aa9 100644
--- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
+++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
@@ -118,7 +118,7 @@
      *
      * See implementation for binary key format.
      *
-     * @removed Use {@link #getTrustedHardwareCertPath} instead.
+     * @deprecated Use {@link #getTrustedHardwareCertPath} instead.
      */
     @Deprecated
     public @NonNull byte[] getTrustedHardwarePublicKey() {
@@ -227,7 +227,7 @@
          *
          * @param publicKey The public key
          * @return This builder.
-         * @removed Use {@link #setTrustedHardwareCertPath} instead.
+         * @deprecated Use {@link #setTrustedHardwareCertPath} instead.
          */
         @Deprecated
         public Builder setTrustedHardwarePublicKey(byte[] publicKey) {
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 2c48bf4..f351c5a 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -288,7 +288,7 @@
     }
 
     /**
-     * @removed Use {@link #initRecoveryService(String, byte[], byte[])} instead.
+     * @deprecated Use {@link #initRecoveryService(String, byte[], byte[])} instead.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -359,7 +359,7 @@
     }
 
     /**
-     * @removed Use {@link #getKeyChainSnapshot()}
+     * @deprecated Use {@link #getKeyChainSnapshot()}
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -435,7 +435,7 @@
     }
 
     /**
-     * @removed Use {@link #getAliases()}.
+     * @deprecated Use {@link #getAliases()}.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -460,7 +460,7 @@
     }
 
     /**
-     * @removed Use {@link #setRecoveryStatus(String, int)}
+     * @deprecated Use {@link #setRecoveryStatus(String, int)}
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -494,7 +494,7 @@
     }
 
     /**
-     * @removed Use {@link #getRecoveryStatus(String)}.
+     * @deprecated Use {@link #getRecoveryStatus(String)}.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -576,7 +576,26 @@
     }
 
     /**
-     * @removed Use {@link #generateKey(String)}.
+     * Deprecated.
+     * Generates a AES256/GCM/NoPADDING key called {@code alias} and loads it into the recoverable
+     * key store. Returns the raw material of the key.
+     *
+     * @param alias The key alias.
+     * @param account The account associated with the key
+     * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery
+     *     service.
+     * @throws LockScreenRequiredException if the user has not set a lock screen. This is required
+     *     to generate recoverable keys, as the snapshots are encrypted using a key derived from the
+     *     lock screen.
+     */
+    @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
+    public byte[] generateAndStoreKey(@NonNull String alias, byte[] account)
+            throws InternalRecoveryServiceException, LockScreenRequiredException {
+        throw new UnsupportedOperationException("Operation is not supported, use generateKey");
+    }
+
+    /**
+     * @deprecated Use {@link #generateKey(String)}.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java
index 87dc6b4..8353389 100644
--- a/core/java/android/security/keystore/recovery/RecoverySession.java
+++ b/core/java/android/security/keystore/recovery/RecoverySession.java
@@ -78,7 +78,7 @@
     }
 
     /**
-     * @removed Use {@link #start(String, CertPath, byte[], byte[], List)} instead.
+     * @deprecated Use {@link #start(String, CertPath, byte[], byte[], List)} instead.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -109,7 +109,7 @@
     }
 
     /**
-     * @removed Use {@link #start(String, CertPath, byte[], byte[], List)} instead.
+     * @deprecated Use {@link #start(String, CertPath, byte[], byte[], List)} instead.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
@@ -198,7 +198,7 @@
     }
 
     /**
-     * @removed Use {@link #recoverKeyChainSnapshot(byte[], List)} instead.
+     * @deprecated Use {@link #recoverKeyChainSnapshot(byte[], List)} instead.
      */
     @Deprecated
     @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE)
diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
index 86419d8..32952db 100644
--- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
+++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java
@@ -75,7 +75,7 @@
         }
 
         /**
-         * @removed AOSP does not associate keys with accounts. This may be done by system app.
+         * @deprecated AOSP does not associate keys with accounts. This may be done by system app.
          */
         @Deprecated
         public Builder setAccount(@NonNull byte[] account) {
@@ -133,7 +133,7 @@
     }
 
     /**
-     * @removed AOSP does not associate keys with accounts. This may be done by system app.
+     * @deprecated AOSP does not associate keys with accounts. This may be done by system app.
      */
     @Deprecated
     public @NonNull byte[] getAccount() {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 5eb7e9c..e03f5fa 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -190,6 +190,10 @@
      */
     public static final String DEBUG_FPS_DIVISOR = "debug.hwui.fps_divisor";
 
+    public static int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101;
+    public static int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102;
+    public static int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
+
     static {
         // Try to check OpenGL support early if possible.
         isAvailable();
@@ -1140,6 +1144,16 @@
         nHackySetRTAnimationsEnabled(divisor <= 1);
     }
 
+    /**
+     * Changes the OpenGL context priority if IMG_context_priority extension is available. Must be
+     * called before any OpenGL context is created.
+     *
+     * @param priority The priority to use. Must be one of EGL_CONTEXT_PRIORITY_* values.
+     */
+    public static void setContextPriority(int priority) {
+        nSetContextPriority(priority);
+    }
+
     /** Not actually public - internal use only. This doc to make lint happy */
     public static native void disableVsync();
 
@@ -1213,4 +1227,5 @@
     private static native void nHackySetRTAnimationsEnabled(boolean enabled);
     private static native void nSetDebuggingEnabled(boolean enabled);
     private static native void nSetIsolatedProcess(boolean enabled);
+    private static native void nSetContextPriority(int priority);
 }
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index fc94b1f..c211e94 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2455,14 +2455,6 @@
         return mWebViewThread;
     }
 
-    /**
-     * Returns the {@link Looper} corresponding to the thread on which WebView calls must be made.
-     */
-    @NonNull
-    public Looper getLooper() {
-        return mWebViewThread;
-    }
-
     //-------------------------------------------------------------------------
     // Interface for WebView providers
     //-------------------------------------------------------------------------
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 451f278..7481f1c 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -992,6 +992,10 @@
     Properties::isolatedProcess = isolated;
 }
 
+static void android_view_ThreadedRenderer_setContextPriority(JNIEnv*, jclass,
+        jint contextPriority) {
+    Properties::contextPriority = contextPriority;
+}
 
 // ----------------------------------------------------------------------------
 // FrameMetricsObserver
@@ -1103,6 +1107,7 @@
             (void*)android_view_ThreadedRenderer_hackySetRTAnimationsEnabled },
     { "nSetDebuggingEnabled", "(Z)V", (void*)android_view_ThreadedRenderer_setDebuggingEnabled },
     { "nSetIsolatedProcess", "(Z)V", (void*)android_view_ThreadedRenderer_setIsolatedProcess },
+    { "nSetContextPriority", "(I)V", (void*)android_view_ThreadedRenderer_setContextPriority },
 };
 
 static JavaVM* mJvm = nullptr;
diff --git a/core/res/res/anim/activity_translucent_close_exit.xml b/core/res/res/anim/activity_translucent_close_exit.xml
index 04c5dea..02df0ff 100644
--- a/core/res/res/anim/activity_translucent_close_exit.xml
+++ b/core/res/res/anim/activity_translucent_close_exit.xml
@@ -20,6 +20,6 @@
     <translate
         android:fromYDelta="0%"
         android:toYDelta="100%"
-        android:interpolator="@interpolator/fast_out_linear_in"
-        android:duration="300"/>
+        android:interpolator="@interpolator/accelerate_quad"
+        android:duration="250"/>
 </set>
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 1602b4b..0a6c45b 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -65,6 +65,8 @@
 bool Properties::debuggingEnabled = false;
 bool Properties::isolatedProcess = false;
 
+int Properties::contextPriority = 0;
+
 static int property_get_int(const char* key, int defaultValue) {
     char buf[PROPERTY_VALUE_MAX] = {
             '\0',
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 81a3657..764c502 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -271,6 +271,8 @@
     ANDROID_API static bool debuggingEnabled;
     ANDROID_API static bool isolatedProcess;
 
+    ANDROID_API static int contextPriority;
+
 private:
     static ProfileType sProfileType;
     static bool sDisableProfileBars;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 5b87e10..6e239e3 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -82,6 +82,7 @@
     bool pixelFormatFloat = false;
     bool glColorSpace = false;
     bool scRGB = false;
+    bool contextPriority = false;
 } EglExtensions;
 
 EglManager::EglManager(RenderThread& thread)
@@ -168,6 +169,7 @@
 #else
     EglExtensions.scRGB = extensions.has("EGL_EXT_gl_colorspace_scrgb");
 #endif
+    EglExtensions.contextPriority = extensions.has("EGL_IMG_context_priority");
 }
 
 bool EglManager::hasEglContext() {
@@ -247,10 +249,18 @@
 }
 
 void EglManager::createContext() {
-    EGLint attribs[] = {EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE};
+    std::vector<EGLint> contextAttributes;
+    contextAttributes.reserve(5);
+    contextAttributes.push_back(EGL_CONTEXT_CLIENT_VERSION);
+    contextAttributes.push_back(GLES_VERSION);
+    if (Properties::contextPriority != 0 && EglExtensions.contextPriority) {
+        contextAttributes.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
+        contextAttributes.push_back(Properties::contextPriority);
+    }
+    contextAttributes.push_back(EGL_NONE);
     mEglContext = eglCreateContext(
             mEglDisplay, EglExtensions.noConfigContext ? ((EGLConfig) nullptr) : mEglConfig,
-            EGL_NO_CONTEXT, attribs);
+            EGL_NO_CONTEXT, contextAttributes.data());
     LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT, "Failed to create context, error = %s",
                         eglErrorString());
 }
diff --git a/packages/InputDevices/res/raw/keyboard_layout_polish.kcm b/packages/InputDevices/res/raw/keyboard_layout_polish.kcm
new file mode 100644
index 0000000..559ec07
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_polish.kcm
@@ -0,0 +1,327 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Polish (qwerty) keyboard layout.
+#
+
+type OVERLAY
+
+### ROW 1
+
+key GRAVE {
+    label:                              '`'
+    base:                               '`'
+    shift:                              '~'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '@'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '$'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '^'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '&'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '*'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              '('
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              ')'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+    ralt:                               '\u0119'
+    ralt+shift, ralt+capslock:          '\u0118'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift, capslock:                    'O'
+    ralt:                               '\u00F3'
+    ralt+shift, ralt+capslock:          '\u00D3'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key LEFT_BRACKET {
+    label:                              '['
+    base:                               '['
+    shift:                              '{'
+}
+
+key RIGHT_BRACKET {
+    label:                              ']'
+    base:                               ']'
+    shift:                              '}'
+}
+
+key BACKSLASH {
+    label:                              '\\'
+    base:                               '\\'
+    shift:                              '|'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+    ralt:                               '\u0105'
+    ralt+shift, ralt+capslock:          '\u0104'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+    ralt:                               '\u015b'
+    ralt+shift, ralt+capslock:          '\u015a'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+    ralt:                               '\u0142'
+    ralt+shift, ralt+capslock:          '\u0141'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base:                               ';'
+    shift:                              ':'
+}
+
+key APOSTROPHE {
+    label:                              '\''
+    base:                               '\''
+    shift:                              '"'
+}
+
+### ROW 4
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+    ralt:                               '\u017c'
+    ralt+shift, ralt+capslock:          '\u017b'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+    ralt:                               '\u017a'
+    ralt+shift, ralt+capslock:          '\u0179'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+    ralt:                               '\u0107'
+    ralt+shift, ralt+capslock:          '\u0106'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+    ralt:                               '\u0144'
+    ralt+shift, ralt+capslock:          '\u0143'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              '<'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              '>'
+}
+
+key SLASH {
+    label:                              '/'
+    base:                               '/'
+    shift:                              '?'
+}
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 61d3234..5fdc4a6 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -125,4 +125,7 @@
 
     <!-- Azerbaijani keyboard layout label. [CHAR LIMIT=35] -->
     <string name="keyboard_layout_azerbaijani">Azerbaijani</string>
+
+    <!-- Polish keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_polish">Polish</string>
 </resources>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index c6bfc1f..1807aea 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -159,4 +159,8 @@
     <keyboard-layout android:name="keyboard_layout_azerbaijani"
             android:label="@string/keyboard_layout_azerbaijani"
             android:keyboardLayout="@raw/keyboard_layout_azerbaijani" />
+
+    <keyboard-layout android:name="keyboard_layout_polish"
+            android:label="@string/keyboard_layout_polish"
+            android:keyboardLayout="@raw/keyboard_layout_polish" />
 </keyboard-layouts>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index 34a099c..00ee575 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -195,8 +195,10 @@
                 if (DEBUG) Log.d(TAG, "Adding local HEADSET profile");
                 mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter,
                         mDeviceManager, this);
-                addProfile(mHeadsetProfile, HeadsetProfile.NAME,
-                        BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+                addHeadsetProfile(mHeadsetProfile, HeadsetProfile.NAME,
+                        BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED,
+                        BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED,
+                        BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
             }
         } else if (mHeadsetProfile != null) {
             Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing.");
@@ -208,8 +210,10 @@
                 if(DEBUG) Log.d(TAG, "Adding local HfpClient profile");
                 mHfpClientProfile =
                     new HfpClientProfile(mContext, mLocalAdapter, mDeviceManager, this);
-                addProfile(mHfpClientProfile, HfpClientProfile.NAME,
-                        BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED);
+                addHeadsetProfile(mHfpClientProfile, HfpClientProfile.NAME,
+                        BluetoothHeadsetClient.ACTION_CONNECTION_STATE_CHANGED,
+                        BluetoothHeadsetClient.ACTION_AUDIO_STATE_CHANGED,
+                        BluetoothHeadsetClient.STATE_AUDIO_DISCONNECTED);
             }
         } else if (mHfpClientProfile != null) {
             Log.w(TAG,
@@ -277,6 +281,15 @@
         // There is no local SDP record for HID and Settings app doesn't control PBAP Server.
     }
 
+    private void addHeadsetProfile(LocalBluetoothProfile profile, String profileName,
+            String stateChangedAction, String audioStateChangedAction, int audioDisconnectedState) {
+        BluetoothEventManager.Handler handler = new HeadsetStateChangeHandler(
+                profile, audioStateChangedAction, audioDisconnectedState);
+        mEventManager.addProfileHandler(stateChangedAction, handler);
+        mEventManager.addProfileHandler(audioStateChangedAction, handler);
+        mProfileNameMap.put(profileName, profile);
+    }
+
     private final Collection<ServiceListener> mServiceListeners =
             new ArrayList<ServiceListener>();
 
@@ -323,18 +336,47 @@
                 cachedDevice = mDeviceManager.addDevice(mLocalAdapter,
                         LocalBluetoothProfileManager.this, device);
             }
+            onReceiveInternal(intent, cachedDevice);
+        }
+
+        protected void onReceiveInternal(Intent intent, CachedBluetoothDevice cachedDevice) {
             int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
             int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
             if (newState == BluetoothProfile.STATE_DISCONNECTED &&
                     oldState == BluetoothProfile.STATE_CONNECTING) {
                 Log.i(TAG, "Failed to connect " + mProfile + " device");
             }
-
             cachedDevice.onProfileStateChanged(mProfile, newState);
             cachedDevice.refresh();
         }
     }
 
+    /** Connectivity and audio state change handler for headset profiles. */
+    private class HeadsetStateChangeHandler extends StateChangedHandler {
+        private final String mAudioChangeAction;
+        private final int mAudioDisconnectedState;
+
+        HeadsetStateChangeHandler(LocalBluetoothProfile profile, String audioChangeAction,
+                int audioDisconnectedState) {
+            super(profile);
+            mAudioChangeAction = audioChangeAction;
+            mAudioDisconnectedState = audioDisconnectedState;
+        }
+
+        @Override
+        public void onReceiveInternal(Intent intent, CachedBluetoothDevice cachedDevice) {
+            if (mAudioChangeAction.equals(intent.getAction())) {
+                int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
+                if (newState != mAudioDisconnectedState) {
+                    cachedDevice.onProfileStateChanged(mProfile, BluetoothProfile.STATE_CONNECTED);
+                }
+                cachedDevice.refresh();
+            } else {
+                super.onReceiveInternal(intent, cachedDevice);
+            }
+        }
+    }
+
     /** State change handler for NAP and PANU profiles. */
     private class PanStateChangedHandler extends StateChangedHandler {
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ThreadedRendererCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ThreadedRendererCompat.java
new file mode 100644
index 0000000..bf88a29
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ThreadedRendererCompat.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.shared.system;
+
+import android.view.ThreadedRenderer;
+
+/**
+ * @see ThreadedRenderer
+ */
+public class ThreadedRendererCompat {
+
+    public static int EGL_CONTEXT_PRIORITY_HIGH_IMG = 0x3101;
+    public static int EGL_CONTEXT_PRIORITY_MEDIUM_IMG = 0x3102;
+    public static int EGL_CONTEXT_PRIORITY_LOW_IMG = 0x3103;
+
+    public static void setContextPriority(int priority) {
+        ThreadedRenderer.setContextPriority(priority);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
index f740654..e4e9701 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/SystemUpdatePolicyTest.java
@@ -24,7 +24,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.app.admin.FreezeInterval;
+import android.app.admin.FreezePeriod;
 import android.app.admin.SystemUpdatePolicy;
 import android.os.Parcel;
 import android.support.test.runner.AndroidJUnit4;
@@ -42,15 +42,15 @@
 import java.io.ByteArrayOutputStream;
 import java.io.InputStreamReader;
 import java.nio.charset.StandardCharsets;
-import java.time.Instant;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
-import java.time.LocalTime;
+import java.time.MonthDay;
 import java.time.ZoneId;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
+
 /**
  * Unit tests for {@link android.app.admin.SystemUpdatePolicy}.
  * Throughout this test, we use "MM-DD" format to denote dates without year.
@@ -224,36 +224,36 @@
 
     @Test
     public void testDistanceWithoutLeapYear() {
-        assertEquals(364, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(364, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2016, 12, 31), LocalDate.of(2016, 1, 1)));
-        assertEquals(365, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(365, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2017, 1, 1), LocalDate.of(2016, 1, 1)));
-        assertEquals(365, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(365, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2017, 2, 28), LocalDate.of(2016, 2, 29)));
-        assertEquals(-365, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(-365, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2016, 1, 1), LocalDate.of(2017, 1, 1)));
-        assertEquals(1, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(1, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 29)));
-        assertEquals(1, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(1, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2016, 3, 1), LocalDate.of(2016, 2, 28)));
-        assertEquals(0, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(0, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2016, 2, 29), LocalDate.of(2016, 2, 28)));
-        assertEquals(0, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(0, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2016, 2, 28), LocalDate.of(2016, 2, 28)));
 
-        assertEquals(59, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(59, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2016, 3, 1), LocalDate.of(2016, 1, 1)));
-        assertEquals(59, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(59, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2017, 3, 1), LocalDate.of(2017, 1, 1)));
 
-        assertEquals(365 * 40, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(365 * 40, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2040, 1, 1), LocalDate.of(2000, 1, 1)));
 
-        assertEquals(365 * 2, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(365 * 2, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2019, 3, 1), LocalDate.of(2017, 3, 1)));
-        assertEquals(365 * 2, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(365 * 2, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2018, 3, 1), LocalDate.of(2016, 3, 1)));
-        assertEquals(365 * 2, FreezeInterval.distanceWithoutLeapYear(
+        assertEquals(365 * 2, FreezePeriod.distanceWithoutLeapYear(
                 LocalDate.of(2017, 3, 1), LocalDate.of(2015, 3, 1)));
 
     }
@@ -386,10 +386,10 @@
 
         // Two freeze periods
         p = SystemUpdatePolicy.createAutomaticInstallPolicy();
-        setFreezePeriods(p, "05-01", "06-01", "11-01", "01-29");
-        // automatic policy for July, August, September and October
+        setFreezePeriods(p, "05-01", "06-01", "10-15", "01-10");
+        // automatic policy for July, August, September and October until 15th
         assertInstallationOption(
-                SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(92),
+                SystemUpdatePolicy.TYPE_INSTALL_AUTOMATIC, TimeUnit.DAYS.toMillis(31 + 30 + 14),
                 millis_2018_08_01, p);
     }
 
@@ -435,18 +435,18 @@
             String... dates) throws Exception {
         SystemUpdatePolicy p = SystemUpdatePolicy.createPostponeInstallPolicy();
         setFreezePeriods(p, dates);
-        p.validateAgainstPreviousFreezePeriod(parseDate(prevStart), parseDate(prevEnd),
-                parseDate(now));
+        p.validateAgainstPreviousFreezePeriod(parseLocalDate(prevStart),
+                parseLocalDate(prevEnd), parseLocalDate(now));
     }
 
     // "MM-DD" format for date
     private void setFreezePeriods(SystemUpdatePolicy policy, String... dates) throws Exception {
-        List<Pair<Integer, Integer>> periods = new ArrayList<>();
-        LocalDate lastDate = null;
+        List<FreezePeriod> periods = new ArrayList<>();
+        MonthDay lastDate = null;
         for (String date : dates) {
-            LocalDate currentDate = parseDate(date);
+            MonthDay currentDate = parseMonthDay(date);
             if (lastDate != null) {
-                periods.add(new Pair<>(lastDate.getDayOfYear(), currentDate.getDayOfYear()));
+                periods.add(new FreezePeriod(lastDate, currentDate));
                 lastDate = null;
             } else {
                 lastDate = currentDate;
@@ -457,7 +457,7 @@
     }
 
     private void testSerialization(SystemUpdatePolicy policy,
-            List<Pair<Integer, Integer>> expectedPeriods) throws Exception {
+            List<FreezePeriod> expectedPeriods) throws Exception {
         // Test parcel / unparcel
         Parcel parcel = Parcel.obtain();
         policy.writeToParcel(parcel, 0);
@@ -485,36 +485,27 @@
     }
 
     private void checkFreezePeriods(SystemUpdatePolicy policy,
-            List<Pair<Integer, Integer>> expectedPeriods) {
+            List<FreezePeriod> expectedPeriods) {
         int i = 0;
-        for (Pair<Integer, Integer> period : policy.getFreezePeriods()) {
-            assertEquals(expectedPeriods.get(i).first, period.first);
-            assertEquals(expectedPeriods.get(i).second, period.second);
+        for (FreezePeriod period : policy.getFreezePeriods()) {
+            assertEquals(expectedPeriods.get(i).getStart(), period.getStart());
+            assertEquals(expectedPeriods.get(i).getEnd(), period.getEnd());
             i++;
         }
     }
 
-    private LocalDate parseDate(String date) {
-        // Use leap year when parsing date string to handle "02-29", but force round down
-        // to Feb 28th by overriding the year to non-leap year.
-        final int year;
-        boolean monthDateOnly = false;
-        if (date.length() == 5) {
-            year = 2000;
-            monthDateOnly = true;
-        } else {
-            year = Integer.parseInt(date.substring(0, 4));
-            date = date.substring(5);
-        }
-        LocalDate result = LocalDate.of(year, Integer.parseInt(date.substring(0, 2)),
+    // MonthDay is of format MM-dd
+    private MonthDay parseMonthDay(String date) {
+        return MonthDay.of(Integer.parseInt(date.substring(0, 2)),
                 Integer.parseInt(date.substring(3, 5)));
-        if (monthDateOnly) {
-            return result.withYear(2001);
-        } else {
-            return result;
-        }
     }
 
+    // LocalDat is of format YYYY-MM-dd
+    private LocalDate parseLocalDate(String date) {
+        return parseMonthDay(date.substring(5)).atYear(Integer.parseInt(date.substring(0, 4)));
+    }
+
+
     private long toMillis(int year, int month, int day) {
         return LocalDateTime.of(year, month, day, 0, 0, 0).atZone(ZoneId.systemDefault())
                 .toInstant().toEpochMilli();