Merge "Added check for misprovisioned Pixel 2 device." into pi-dev
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 8ffe5bf..ed6c25d 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -302,6 +302,7 @@
     mHeight = h;
     mFlingerSurfaceControl = control;
     mFlingerSurface = s;
+    mTargetInset = -1;
 
     // If the device has encryption turned on or is in process
     // of being encrypted we show the encrypted boot animation.
@@ -942,6 +943,7 @@
                 if (mClockEnabled && mTimeIsAccurate && validClock(part)) {
                     drawClock(animation.clockFont, part.clockPosX, part.clockPosY);
                 }
+                handleViewport(frameDuration);
 
                 eglSwapBuffers(mDisplay, mSurface);
 
@@ -966,7 +968,7 @@
             usleep(part.pause * ns2us(frameDuration));
 
             // For infinite parts, we've now played them at least once, so perhaps exit
-            if(exitPending() && !part.count)
+            if(exitPending() && !part.count && mCurrentInset >= mTargetInset)
                 break;
         }
 
@@ -986,6 +988,51 @@
     return true;
 }
 
+void BootAnimation::handleViewport(nsecs_t timestep) {
+    if (mShuttingDown || !mFlingerSurfaceControl || mTargetInset == 0) {
+        return;
+    }
+    if (mTargetInset < 0) {
+        // Poll the amount for the top display inset. This will return -1 until persistent properties
+        // have been loaded.
+        mTargetInset = android::base::GetIntProperty("persist.sys.displayinset.top",
+                -1 /* default */, -1 /* min */, mHeight / 2 /* max */);
+    }
+    if (mTargetInset <= 0) {
+        return;
+    }
+
+    if (mCurrentInset < mTargetInset) {
+        // After the device boots, the inset will effectively be cropped away. We animate this here.
+        float fraction = static_cast<float>(mCurrentInset) / mTargetInset;
+        int interpolatedInset = (cosf((fraction + 1) * M_PI) / 2.0f + 0.5f) * mTargetInset;
+
+        SurfaceComposerClient::Transaction()
+                .setCrop(mFlingerSurfaceControl, Rect(0, interpolatedInset, mWidth, mHeight))
+                .apply();
+    } else {
+        // At the end of the animation, we switch to the viewport that DisplayManager will apply
+        // later. This changes the coordinate system, and means we must move the surface up by
+        // the inset amount.
+        sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
+                ISurfaceComposer::eDisplayIdMain));
+
+        Rect layerStackRect(0, 0, mWidth, mHeight - mTargetInset);
+        Rect displayRect(0, mTargetInset, mWidth, mHeight);
+
+        SurfaceComposerClient::Transaction t;
+        t.setPosition(mFlingerSurfaceControl, 0, -mTargetInset)
+                .setCrop(mFlingerSurfaceControl, Rect(0, mTargetInset, mWidth, mHeight));
+        t.setDisplayProjection(dtoken, 0 /* orientation */, layerStackRect, displayRect);
+        t.apply();
+
+        mTargetInset = mCurrentInset = 0;
+    }
+
+    int delta = timestep * mTargetInset / ms2ns(200);
+    mCurrentInset += delta;
+}
+
 void BootAnimation::releaseAnimation(Animation* animation) const
 {
     for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 56e131523..b4699d8 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -157,11 +157,15 @@
 
     void checkExit();
 
+    void handleViewport(nsecs_t timestep);
+
     sp<SurfaceComposerClient>       mSession;
     AssetManager mAssets;
     Texture     mAndroid[2];
     int         mWidth;
     int         mHeight;
+    int         mCurrentInset;
+    int         mTargetInset;
     bool        mUseNpotTextures = false;
     EGLDisplay  mDisplay;
     EGLDisplay  mContext;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a6d2be0..68e8a52 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -6338,6 +6338,10 @@
     }
 
     void dumpInner(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
+        if (args != null && args.length > 0 && args[0].equals("--autofill")) {
+            dumpAutofillManager(prefix, writer);
+            return;
+        }
         writer.print(prefix); writer.print("Local Activity ");
                 writer.print(Integer.toHexString(System.identityHashCode(this)));
                 writer.println(" State:");
@@ -6365,16 +6369,20 @@
 
         mHandler.getLooper().dump(new PrintWriterPrinter(writer), prefix);
 
+        dumpAutofillManager(prefix, writer);
+
+        ResourcesManager.getInstance().dump(prefix, writer);
+    }
+
+    void dumpAutofillManager(String prefix, PrintWriter writer) {
         final AutofillManager afm = getAutofillManager();
         if (afm != null) {
+            afm.dump(prefix, writer);
             writer.print(prefix); writer.print("Autofill Compat Mode: ");
             writer.println(isAutofillCompatibilityEnabled());
-            afm.dump(prefix, writer);
         } else {
             writer.print(prefix); writer.println("No AutofillManager");
         }
-
-        ResourcesManager.getInstance().dump(prefix, writer);
     }
 
     /**
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 9b6764d..14cae95 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -413,4 +413,9 @@
      * @return The intent used to launch the home activity.
      */
     public abstract Intent getHomeIntent();
+
+    /**
+     * WindowManager notifies AM when display size of the default display changes.
+     */
+    public abstract void notifyDefaultDisplaySizeChanged();
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 87b3349..ab0b88c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -146,6 +146,7 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.org.conscrypt.OpenSSLSocketImpl;
 import com.android.org.conscrypt.TrustedCertificateStore;
@@ -5144,6 +5145,16 @@
         }
     }
 
+    /**
+     * Updates the application info.
+     *
+     * This only works in the system process. Must be called on the main thread.
+     */
+    public void handleSystemApplicationInfoChanged(@NonNull ApplicationInfo ai) {
+        Preconditions.checkState(mSystemThread, "Must only be called in the system process");
+        handleApplicationInfoChanged(ai);
+    }
+
     void handleApplicationInfoChanged(@NonNull final ApplicationInfo ai) {
         // Updates triggered by package installation go through a package update
         // receiver. Here we try to capture ApplicationInfo changes that are
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 30256b4..8d0ad33 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -121,10 +121,13 @@
         }
     }
 
+    private static final boolean ENABLE_APK_ASSETS_CACHE = false;
+
     /**
      * The ApkAssets we are caching and intend to hold strong references to.
      */
-    private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets = new LruCache<>(3);
+    private final LruCache<ApkKey, ApkAssets> mLoadedApkAssets =
+            (ENABLE_APK_ASSETS_CACHE) ? new LruCache<>(3) : null;
 
     /**
      * The ApkAssets that are being referenced in the wild that we can reuse, even if they aren't
@@ -310,9 +313,12 @@
     private @NonNull ApkAssets loadApkAssets(String path, boolean sharedLib, boolean overlay)
             throws IOException {
         final ApkKey newKey = new ApkKey(path, sharedLib, overlay);
-        ApkAssets apkAssets = mLoadedApkAssets.get(newKey);
-        if (apkAssets != null) {
-            return apkAssets;
+        ApkAssets apkAssets = null;
+        if (mLoadedApkAssets != null) {
+            apkAssets = mLoadedApkAssets.get(newKey);
+            if (apkAssets != null) {
+                return apkAssets;
+            }
         }
 
         // Optimistically check if this ApkAssets exists somewhere else.
@@ -320,7 +326,10 @@
         if (apkAssetsRef != null) {
             apkAssets = apkAssetsRef.get();
             if (apkAssets != null) {
-                mLoadedApkAssets.put(newKey, apkAssets);
+                if (mLoadedApkAssets != null) {
+                    mLoadedApkAssets.put(newKey, apkAssets);
+                }
+
                 return apkAssets;
             } else {
                 // Clean up the reference.
@@ -335,7 +344,11 @@
         } else {
             apkAssets = ApkAssets.loadFromPath(path, false /*system*/, sharedLib);
         }
-        mLoadedApkAssets.put(newKey, apkAssets);
+
+        if (mLoadedApkAssets != null) {
+            mLoadedApkAssets.put(newKey, apkAssets);
+        }
+
         mCachedApkAssets.put(newKey, new WeakReference<>(apkAssets));
         return apkAssets;
     }
@@ -434,18 +447,22 @@
 
             pw.println("ResourcesManager:");
             pw.increaseIndent();
-            pw.print("cached apks: total=");
-            pw.print(mLoadedApkAssets.size());
-            pw.print(" created=");
-            pw.print(mLoadedApkAssets.createCount());
-            pw.print(" evicted=");
-            pw.print(mLoadedApkAssets.evictionCount());
-            pw.print(" hit=");
-            pw.print(mLoadedApkAssets.hitCount());
-            pw.print(" miss=");
-            pw.print(mLoadedApkAssets.missCount());
-            pw.print(" max=");
-            pw.print(mLoadedApkAssets.maxSize());
+            if (mLoadedApkAssets != null) {
+                pw.print("cached apks: total=");
+                pw.print(mLoadedApkAssets.size());
+                pw.print(" created=");
+                pw.print(mLoadedApkAssets.createCount());
+                pw.print(" evicted=");
+                pw.print(mLoadedApkAssets.evictionCount());
+                pw.print(" hit=");
+                pw.print(mLoadedApkAssets.hitCount());
+                pw.print(" miss=");
+                pw.print(mLoadedApkAssets.missCount());
+                pw.print(" max=");
+                pw.print(mLoadedApkAssets.maxSize());
+            } else {
+                pw.print("cached apks: 0 [cache disabled]");
+            }
             pw.println();
 
             pw.print("total apks: ");
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index d568662..dd61f28 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -41,18 +41,23 @@
 import java.util.List;
 
 /**
- * Assist data automatically created by the platform's implementation of assist and autofill.
+ * <p>This API automatically creates assist data from the platform's
+ * implementation of assist and autofill.
  *
  * <p>The structure is used for assist purposes when created by
  * {@link android.app.Activity#onProvideAssistData}, {@link View#onProvideStructure(ViewStructure)},
  * or {@link View#onProvideVirtualStructure(ViewStructure)}.
  *
- * <p>The structure is used for autofill purposes when created by
+ * <p>The structure is also used for autofill purposes when created by
  * {@link View#onProvideAutofillStructure(ViewStructure, int)},
  * or {@link View#onProvideAutofillVirtualStructure(ViewStructure, int)}.
  *
- * <p>For performance reasons, some properties of the assist data might be available just for assist
- * or autofill purposes; in those case, the property availability will be document in its javadoc.
+ * <p>For performance reasons, some properties of the assist data might only be available for
+ * assist or autofill purposes. In those cases, a property's availability will be documented
+ * in its javadoc.
+ *
+ * <p>To learn about using Autofill in your app, read the
+ * <a href="/guide/topics/text/autofill">Autofill Framework</a> guides.
  */
 public class AssistStructure implements Parcelable {
     static final String TAG = "AssistStructure";
diff --git a/core/java/android/appwidget/AppWidgetManagerInternal.java b/core/java/android/appwidget/AppWidgetManagerInternal.java
index 7ab3d8b..5694ca8 100644
--- a/core/java/android/appwidget/AppWidgetManagerInternal.java
+++ b/core/java/android/appwidget/AppWidgetManagerInternal.java
@@ -16,12 +16,9 @@
 
 package android.appwidget;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.util.ArraySet;
 
-import java.util.Set;
-
 /**
  * App widget manager local system service interface.
  *
@@ -36,4 +33,13 @@
      * @return Whether the UID hosts widgets from the package.
      */
     public abstract @Nullable ArraySet<String> getHostedWidgetPackages(int uid);
+
+    /**
+     * Execute the widget-related work of unlocking a user.  This is intentionally
+     * invoked just <em>before</em> the boot-completed broadcast is issued, after
+     * the data-related work of unlock has completed.
+     *
+     * @param userId The user that is being unlocked.
+     */
+    public abstract void unlockUser(int userId);
 }
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index d6d9764..e6b6acf 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -39,11 +39,18 @@
 public final class SQLiteGlobal {
     private static final String TAG = "SQLiteGlobal";
 
+    /** @hide */
+    public static final String SYNC_MODE_FULL = "FULL";
+
     private static final Object sLock = new Object();
+
     private static int sDefaultPageSize;
 
     private static native int nativeReleaseMemory();
 
+    /** @hide */
+    public static volatile String sDefaultSyncMode;
+
     private SQLiteGlobal() {
     }
 
@@ -103,6 +110,11 @@
      * Gets the default database synchronization mode when WAL is not in use.
      */
     public static String getDefaultSyncMode() {
+        // Use the FULL synchronous mode for system processes by default.
+        String defaultMode = sDefaultSyncMode;
+        if (defaultMode != null) {
+            return defaultMode;
+        }
         return SystemProperties.get("debug.sqlite.syncmode",
                 Resources.getSystem().getString(
                 com.android.internal.R.string.db_default_sync_mode));
@@ -112,6 +124,11 @@
      * Gets the database synchronization mode when in WAL mode.
      */
     public static String getWALSyncMode() {
+        // Use the FULL synchronous mode for system processes by default.
+        String defaultMode = sDefaultSyncMode;
+        if (defaultMode != null) {
+            return defaultMode;
+        }
         return SystemProperties.get("debug.sqlite.wal.syncmode",
                 Resources.getSystem().getString(
                 com.android.internal.R.string.db_wal_sync_mode));
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 1275a85..caa99d5 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -819,11 +819,11 @@
      * camera in the list of supported camera devices.</p>
      * <p>This capability requires the camera device to support the following:</p>
      * <ul>
-     * <li>This camera device must list the following static metadata entries in {@link android.hardware.camera2.CameraCharacteristics }:<ul>
-     * <li>android.logicalMultiCamera.physicalIds</li>
-     * <li>{@link CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE android.logicalMultiCamera.sensorSyncType}</li>
-     * </ul>
-     * </li>
+     * <li>The IDs of underlying physical cameras are returned via
+     *   {@link android.hardware.camera2.CameraCharacteristics#getPhysicalCameraIds }.</li>
+     * <li>This camera device must list static metadata
+     *   {@link CameraCharacteristics#LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE android.logicalMultiCamera.sensorSyncType} in
+     *   {@link android.hardware.camera2.CameraCharacteristics }.</li>
      * <li>The underlying physical cameras' static metadata must list the following entries,
      *   so that the application can correlate pixels from the physical streams:<ul>
      * <li>{@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference}</li>
diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java
index 5211767..f8408be 100644
--- a/core/java/android/service/autofill/Dataset.java
+++ b/core/java/android/service/autofill/Dataset.java
@@ -33,8 +33,13 @@
 import java.util.regex.Pattern;
 
 /**
- * A dataset object represents a group of fields (key / value pairs) used to autofill parts of a
- * screen.
+ * <p>A <code>Dataset</code> object represents a group of fields (key / value pairs) used
+ * to autofill parts of a screen.
+ *
+ * <p>For more information about the role of datasets in the autofill workflow, read
+ * <a href="/guide/topics/text/autofill-services">Build autofill services</a> and the
+ * <code><a href="/reference/android/service/autofill/AutofillService">AutofillService</a></code>
+ * documentation.
  *
  * <a name="BasicUsage"></a>
  * <h3>Basic usage</h3>
@@ -88,10 +93,6 @@
  *   <li>All other datasets are hidden.
  * </ol>
  *
- * <a name="MoreInfo"></a>
- * <h3>More information</h3>
- * <p>See {@link android.service.autofill.AutofillService} for more information and examples about
- * the role of datasets in the autofill workflow.
  */
 public final class Dataset implements Parcelable {
 
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 0257891..1695c13 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -21,8 +21,11 @@
 import android.os.RemoteException;
 
 /**
- * Handles autofill requests from the {@link AutofillService} into the {@link Activity} being
- * autofilled.
+ * <p><code>FillCallback</code> handles autofill requests from the {@link AutofillService} into
+ * the {@link Activity} being autofilled.
+ *
+ * <p>To learn about using Autofill services in your app, read
+ * <a href="/guide/topics/text/autofill-services">Build autofill services</a>.
  */
 public final class FillCallback {
     private final IFillCallback mCallback;
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 496bc9f..5f80d31 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -325,6 +325,7 @@
      *
      * @hide
      */
+    @VisibleForTesting
     public static DisplayCutout fromBoundingRect(int left, int top, int right, int bottom) {
         Region r = Region.obtain();
         r.set(left, top, right, bottom);
@@ -422,8 +423,11 @@
         m.postTranslate(offsetX, 0);
         p.transform(m);
 
-        addToRegion(p, r);
+        final Rect tmpRect = new Rect();
+        toRectAndAddToRegion(p, r, tmpRect);
+        final int topInset = tmpRect.bottom;
 
+        final int bottomInset;
         if (bottomSpec != null) {
             final Path bottomPath;
             try {
@@ -436,10 +440,17 @@
             m.postTranslate(0, displayHeight);
             bottomPath.transform(m);
             p.addPath(bottomPath);
-            addToRegion(bottomPath, r);
+            toRectAndAddToRegion(bottomPath, r, tmpRect);
+            bottomInset = displayHeight - tmpRect.top;
+        } else {
+            bottomInset = 0;
         }
 
-        final Pair<Path, DisplayCutout> result = new Pair<>(p, fromBounds(r));
+        // Reuse tmpRect as the inset rect we store into the DisplayCutout instance.
+        tmpRect.set(0, topInset, 0, bottomInset);
+        final DisplayCutout cutout = new DisplayCutout(tmpRect, r, false /* copyArguments */);
+
+        final Pair<Path, DisplayCutout> result = new Pair<>(p, cutout);
         synchronized (CACHE_LOCK) {
             sCachedSpec = spec;
             sCachedDisplayWidth = displayWidth;
@@ -450,12 +461,11 @@
         return result;
     }
 
-    private static void addToRegion(Path p, Region r) {
+    private static void toRectAndAddToRegion(Path p, Region inoutRegion, Rect inoutRect) {
         final RectF rectF = new RectF();
-        final Rect rect = new Rect();
         p.computeBounds(rectF, false /* unused */);
-        rectF.round(rect);
-        r.op(rect, Op.UNION);
+        rectF.round(inoutRect);
+        inoutRegion.op(inoutRect, Op.UNION);
     }
 
     private static Region boundingRectsToRegion(List<Rect> rects) {
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 3f7ab2a..38dcdd3 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -33,9 +33,14 @@
 import java.util.List;
 
 /**
- * Container for storing additional per-view data generated by {@link View#onProvideStructure
+ * <p><code>ViewStructure</code> is a container for storing additional
+ * per-view data generated by {@link View#onProvideStructure
  * View.onProvideStructure} and {@link View#onProvideAutofillStructure
  * View.onProvideAutofillStructure}.
+ *
+ * <p>To learn more about using Autofill in your app, read the
+ * <a href="/guide/topics/text/autofill">Autofill Framework</a> guides.
+ *
  */
 public abstract class ViewStructure {
 
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 7555fff..d21cb3e 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -77,11 +77,16 @@
 import sun.misc.Cleaner;
 
 /**
- * The {@link AutofillManager} provides ways for apps and custom views to integrate with the
- * Autofill Framework lifecycle.
+ * <p>The {@link AutofillManager} class provides ways for apps and custom views to
+ * integrate with the Autofill Framework lifecycle.
+ *
+ * <p>To learn about using Autofill in your app, read
+ * the <a href="/guide/topics/text/autofill">Autofill Framework</a> guides.
+ *
+ * <h3 id="autofill-lifecycle">Autofill lifecycle</h3>
  *
  * <p>The autofill lifecycle starts with the creation of an autofill context associated with an
- * activity context; the autofill context is created when one of the following methods is called for
+ * activity context. The autofill context is created when one of the following methods is called for
  * the first time in an activity context, and the current user has an enabled autofill service:
  *
  * <ul>
@@ -90,7 +95,7 @@
  *   <li>{@link #requestAutofill(View)}
  * </ul>
  *
- * <p>Tipically, the context is automatically created when the first view of the activity is
+ * <p>Typically, the context is automatically created when the first view of the activity is
  * focused because {@code View.onFocusChanged()} indirectly calls
  * {@link #notifyViewEntered(View)}. App developers can call {@link #requestAutofill(View)} to
  * explicitly create it (for example, a custom view developer could offer a contextual menu action
@@ -134,7 +139,9 @@
  * shows an autofill save UI if the value of savable views have changed. If the user selects the
  * option to Save, the current value of the views is then sent to the autofill service.
  *
- * <p>It is safe to call into its methods from any thread.
+ * <h3 id="additional-notes">Additional notes</h3>
+ *
+ * <p>It is safe to call <code>AutofillManager</code> methods from any thread.
  */
 @SystemService(Context.AUTOFILL_MANAGER_SERVICE)
 @RequiresFeature(PackageManager.FEATURE_AUTOFILL)
@@ -2138,7 +2145,11 @@
         pw.print(pfx); pw.print("sessionId: "); pw.println(mSessionId);
         pw.print(pfx); pw.print("state: "); pw.println(getStateAsStringLocked());
         pw.print(pfx); pw.print("context: "); pw.println(mContext);
-        pw.print(pfx); pw.print("client: "); pw.println(getClient());
+        final AutofillClient client = getClient();
+        if (client != null) {
+            pw.print(pfx); pw.print("client: "); pw.print(client);
+            pw.print(" ("); pw.print(client.autofillClientGetActivityToken()); pw.println(')');
+        }
         pw.print(pfx); pw.print("enabled: "); pw.println(mEnabled);
         pw.print(pfx); pw.print("hasService: "); pw.println(mService != null);
         pw.print(pfx); pw.print("hasCallback: "); pw.println(mCallback != null);
@@ -2157,8 +2168,24 @@
         pw.print(pfx); pw.print("entered ids: "); pw.println(mEnteredIds);
         pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
         pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
-        pw.print(pfx); pw.print("compat mode enabled: "); pw.println(
-                isCompatibilityModeEnabledLocked());
+        pw.print(pfx); pw.print("compat mode enabled: ");
+        synchronized (mLock) {
+            if (mCompatibilityBridge != null) {
+                final String pfx2 = pfx + "  ";
+                pw.println("true");
+                pw.print(pfx2); pw.print("windowId: ");
+                pw.println(mCompatibilityBridge.mFocusedWindowId);
+                pw.print(pfx2); pw.print("nodeId: ");
+                pw.println(mCompatibilityBridge.mFocusedNodeId);
+                pw.print(pfx2); pw.print("virtualId: ");
+                pw.println(AccessibilityNodeInfo
+                        .getVirtualDescendantId(mCompatibilityBridge.mFocusedNodeId));
+                pw.print(pfx2); pw.print("focusedBounds: ");
+                pw.println(mCompatibilityBridge.mFocusedBounds);
+            } else {
+                pw.println("false");
+            }
+        }
         pw.print(pfx); pw.print("debug: "); pw.print(sDebug);
         pw.print(" verbose: "); pw.println(sVerbose);
     }
@@ -2292,7 +2319,15 @@
         @Override
         public AccessibilityEvent onAccessibilityEvent(AccessibilityEvent event,
                 boolean accessibilityEnabled, int relevantEventTypes) {
-            switch (event.getEventType()) {
+            final int type = event.getEventType();
+            if (sVerbose) {
+                // NOTE: this is waaay spammy, but that's life.
+                Log.v(TAG, "onAccessibilityEvent(" + AccessibilityEvent.eventTypeToString(type)
+                        + "): virtualId="
+                        + AccessibilityNodeInfo.getVirtualDescendantId(event.getSourceNodeId())
+                        + ", client=" + getClient());
+            }
+            switch (type) {
                 case AccessibilityEvent.TYPE_VIEW_FOCUSED: {
                     synchronized (mLock) {
                         if (mFocusedWindowId == event.getWindowId()
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index 64b1f24..0c8613b 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -111,14 +111,16 @@
             final int childHeight = child.getMeasuredHeight();
             int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
                     lp.bottomMargin + spacing);
-            first = false;
             int measureType = MessagingChild.MEASURED_NORMAL;
             if (messagingChild != null) {
                 measureType = messagingChild.getMeasuredType();
                 linesRemaining -= messagingChild.getConsumedLines();
             }
-            boolean isShortened = measureType == MessagingChild.MEASURED_SHORTENED;
-            boolean isTooSmall = measureType == MessagingChild.MEASURED_TOO_SMALL;
+
+            // We never measure the first item as too small, we want to at least show something.
+            boolean isTooSmall = measureType == MessagingChild.MEASURED_TOO_SMALL && !first;
+            boolean isShortened = measureType == MessagingChild.MEASURED_SHORTENED
+                    || measureType == MessagingChild.MEASURED_TOO_SMALL && first;
             if (newHeight <= targetHeight && !isTooSmall) {
                 totalHeight = newHeight;
                 measuredWidth = Math.max(measuredWidth,
@@ -131,6 +133,7 @@
             } else {
                 break;
             }
+            first = false;
         }
 
         setMeasuredDimension(
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fbd7ffb..b372d7b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2984,6 +2984,10 @@
          -->
     <bool name="config_fillMainBuiltInDisplayCutout">false</bool>
 
+    <!-- If true, and there is a cutout on the main built in display, the cutout will be masked
+         by shrinking the display such that it does not overlap the cutout area. -->
+    <bool name="config_maskMainBuiltInDisplayCutout">false</bool>
+
     <!-- Ultrasound support for Mic/speaker path -->
     <!-- Whether the default microphone audio source supports near-ultrasound frequencies
          (range of 18 - 21 kHz). -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 471170b..73cb59e 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -61,6 +61,15 @@
     <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
     <dimen name="status_bar_edge_ignore">5dp</dimen>
 
+    <!-- Default radius of the software rounded corners. -->
+    <dimen name="rounded_corner_radius">0dp</dimen>
+    <!-- Radius of the software rounded corners at the top of the display in its natural
+        orientation. If zero, the value of rounded_corner_radius is used. -->
+    <dimen name="rounded_corner_radius_top">0dp</dimen>
+    <!-- Radius of the software rounded corners at the bottom of the display in its natural
+        orientation. If zero, the value of rounded_corner_radius is used. -->
+    <dimen name="rounded_corner_radius_bottom">0dp</dimen>
+
     <!-- Width of the window of the divider bar used to resize docked stacks. -->
     <dimen name="docked_stack_divider_thickness">48dp</dimen>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ab1e4c1..a3ed1b0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3408,6 +3408,8 @@
   <java-symbol type="integer" name="config_defaultHapticFeedbackIntensity" />
   <java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
 
+  <java-symbol type="bool" name="config_maskMainBuiltInDisplayCutout" />
+
   <java-symbol type="array" name="config_disableApksUnlessMatchedSku_apk_list" />
   <java-symbol type="array" name="config_disableApkUnlessMatchedSku_skus_list" />
 
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 4833816..090f9af 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -306,6 +306,7 @@
         <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.QuickContactBadgeSmall.WindowLarge</item>
         <item name="listPopupWindowStyle">@style/Widget.ListPopupWindow</item>
         <item name="popupMenuStyle">@style/Widget.PopupMenu</item>
+        <item name="popupTheme">@null</item>
         <item name="activityChooserViewStyle">@style/Widget.ActivityChooserView</item>
         <item name="fragmentBreadCrumbsStyle">@style/Widget.FragmentBreadCrumbs</item>
         <item name="contextPopupMenuStyle">?attr/popupMenuStyle</item>
diff --git a/core/res/res/values/themes_holo.xml b/core/res/res/values/themes_holo.xml
index cb5b93d..33832d4 100644
--- a/core/res/res/values/themes_holo.xml
+++ b/core/res/res/values/themes_holo.xml
@@ -296,6 +296,7 @@
         <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Holo.QuickContactBadgeSmall.WindowLarge</item>
         <item name="listPopupWindowStyle">@style/Widget.Holo.ListPopupWindow</item>
         <item name="popupMenuStyle">@style/Widget.Holo.PopupMenu</item>
+        <item name="popupTheme">@null</item>
         <item name="stackViewStyle">@style/Widget.Holo.StackView</item>
         <item name="activityChooserViewStyle">@style/Widget.Holo.ActivityChooserView</item>
         <item name="fragmentBreadCrumbsStyle">@style/Widget.Holo.FragmentBreadCrumbs</item>
@@ -658,9 +659,11 @@
         <item name="quickContactBadgeStyleSmallWindowLarge">@style/Widget.Holo.QuickContactBadgeSmall.WindowLarge</item>
         <item name="listPopupWindowStyle">@style/Widget.Holo.Light.ListPopupWindow</item>
         <item name="popupMenuStyle">@style/Widget.Holo.Light.PopupMenu</item>
+        <item name="popupTheme">@null</item>
         <item name="stackViewStyle">@style/Widget.Holo.StackView</item>
         <item name="activityChooserViewStyle">@style/Widget.Holo.Light.ActivityChooserView</item>
         <item name="fragmentBreadCrumbsStyle">@style/Widget.Holo.Light.FragmentBreadCrumbs</item>
+        <item name="contextPopupMenuStyle">?attr/popupMenuStyle</item>
 
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@style/Preference.Holo.PreferenceScreen</item>
diff --git a/core/tests/coretests/src/android/view/DisplayCutoutTest.java b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
index 6ee74cb..fe45fe7 100644
--- a/core/tests/coretests/src/android/view/DisplayCutoutTest.java
+++ b/core/tests/coretests/src/android/view/DisplayCutoutTest.java
@@ -19,6 +19,7 @@
 import static android.view.DisplayCutout.NO_CUTOUT;
 import static android.view.DisplayCutout.fromSpec;
 
+import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.not;
 import static org.hamcrest.Matchers.sameInstance;
 import static org.junit.Assert.assertEquals;
@@ -220,6 +221,19 @@
     }
 
     @Test
+    public void fromSpec_setsSafeInsets_top() {
+        DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z", 200, 400, 2f);
+        assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 20, 0, 0)));
+    }
+
+    @Test
+    public void fromSpec_setsSafeInsets_top_and_bottom() {
+        DisplayCutout cutout = fromSpec("M -50,0 v 20 h 100 v -20 z"
+                + "@bottom M -50,0 v -10,0 h 100 v 20 z", 200, 400, 2f);
+        assertThat(cutout.getSafeInsets(), equalTo(new Rect(0, 20, 0, 10)));
+    }
+
+    @Test
     public void parcel_unparcel_nocutout() {
         Parcel p = Parcel.obtain();
 
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 2207a2a..bb7b038 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -404,7 +404,7 @@
  <p>
  The codec in turn will return a read-only output buffer via the {@link
  Callback#onOutputBufferAvailable onOutputBufferAvailable} callback in asynchronous mode, or in
- response to a {@link #dequeueOutputBuffer dequeuOutputBuffer} call in synchronous mode. After the
+ response to a {@link #dequeueOutputBuffer dequeueOutputBuffer} call in synchronous mode. After the
  output buffer has been processed, call one of the {@link #releaseOutputBuffer
  releaseOutputBuffer} methods to return the buffer to the codec.
  <p>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 093b1bd..15cb9bd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -25,6 +25,7 @@
 import android.arch.lifecycle.Lifecycle;
 import android.arch.lifecycle.LifecycleObserver;
 import android.arch.lifecycle.OnLifecycleEvent;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -62,6 +63,7 @@
 import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.text.Collator;
 import java.text.Normalizer;
 import java.text.Normalizer.Form;
@@ -132,7 +134,7 @@
     boolean mSessionsChanged;
 
     // Temporary for dispatching session callbacks.  Only touched by main thread.
-    final ArrayList<Session> mActiveSessions = new ArrayList<Session>();
+    final ArrayList<WeakReference<Session>> mActiveSessions = new ArrayList<>();
 
     final HandlerThread mThread;
     final BackgroundHandler mBackgroundHandler;
@@ -618,7 +620,7 @@
             for (int i=0; i<mSessions.size(); i++) {
                 Session s = mSessions.get(i);
                 if (s.mResumed) {
-                    mActiveSessions.add(s);
+                    mActiveSessions.add(new WeakReference<>(s));
                 }
             }
         }
@@ -830,46 +832,70 @@
             rebuildActiveSessions();
             switch (msg.what) {
                 case MSG_REBUILD_COMPLETE: {
-                    Session s = (Session)msg.obj;
-                    if (mActiveSessions.contains(s)) {
-                        s.mCallbacks.onRebuildComplete(s.mLastAppList);
+                    Session s = (Session) msg.obj;
+                    for (WeakReference<Session> sessionRef : mActiveSessions) {
+                        final Session session = sessionRef.get();
+                        if (session != null && session == s) {
+                            s.mCallbacks.onRebuildComplete(s.mLastAppList);
+                        }
                     }
                 } break;
                 case MSG_PACKAGE_LIST_CHANGED: {
-                    for (int i=0; i<mActiveSessions.size(); i++) {
-                        mActiveSessions.get(i).mCallbacks.onPackageListChanged();
+                    for (WeakReference<Session> sessionRef : mActiveSessions) {
+                        final Session session = sessionRef.get();
+                        if (session != null) {
+                            session.mCallbacks.onPackageListChanged();
+                        }
                     }
                 } break;
                 case MSG_PACKAGE_ICON_CHANGED: {
-                    for (int i=0; i<mActiveSessions.size(); i++) {
-                        mActiveSessions.get(i).mCallbacks.onPackageIconChanged();
+                    for (WeakReference<Session> sessionRef : mActiveSessions) {
+                        final Session session = sessionRef.get();
+                        if (session != null) {
+                            session.mCallbacks.onPackageIconChanged();
+                        }
                     }
                 } break;
                 case MSG_PACKAGE_SIZE_CHANGED: {
-                    for (int i=0; i<mActiveSessions.size(); i++) {
-                        mActiveSessions.get(i).mCallbacks.onPackageSizeChanged(
-                                (String)msg.obj);
+                    for (WeakReference<Session> sessionRef : mActiveSessions) {
+                        final Session session = sessionRef.get();
+                        if (session != null) {
+                            session.mCallbacks.onPackageSizeChanged(
+                                    (String) msg.obj);
+                        }
                     }
                 } break;
                 case MSG_ALL_SIZES_COMPUTED: {
-                    for (int i=0; i<mActiveSessions.size(); i++) {
-                        mActiveSessions.get(i).mCallbacks.onAllSizesComputed();
+                    for (WeakReference<Session> sessionRef : mActiveSessions) {
+                        final Session session = sessionRef.get();
+                        if (session != null) {
+                            session.mCallbacks.onAllSizesComputed();
+                        }
                     }
                 } break;
                 case MSG_RUNNING_STATE_CHANGED: {
-                    for (int i=0; i<mActiveSessions.size(); i++) {
-                        mActiveSessions.get(i).mCallbacks.onRunningStateChanged(
-                                msg.arg1 != 0);
+                    for (WeakReference<Session> sessionRef : mActiveSessions) {
+                        final Session session = sessionRef.get();
+                        if (session != null) {
+                            session.mCallbacks.onRunningStateChanged(
+                                    msg.arg1 != 0);
+                        }
                     }
                 } break;
                 case MSG_LAUNCHER_INFO_CHANGED: {
-                    for (int i=0; i<mActiveSessions.size(); i++) {
-                        mActiveSessions.get(i).mCallbacks.onLauncherInfoChanged();
+                    for (WeakReference<Session> sessionRef : mActiveSessions) {
+                        final Session session = sessionRef.get();
+                        if (session != null) {
+                            session.mCallbacks.onLauncherInfoChanged();
+                        }
                     }
                 } break;
                 case MSG_LOAD_ENTRIES_COMPLETE: {
-                    for (int i=0; i<mActiveSessions.size(); i++) {
-                        mActiveSessions.get(i).mCallbacks.onLoadEntriesCompleted();
+                    for (WeakReference<Session> sessionRef : mActiveSessions) {
+                        final Session session = sessionRef.get();
+                        if (session != null) {
+                            session.mCallbacks.onLoadEntriesCompleted();
+                        }
                     }
                 } break;
             }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
index 3732471..1c50953 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
@@ -19,6 +19,8 @@
 import android.content.Context;
 import android.util.Log;
 
+import java.lang.ref.WeakReference;
+
 /**
  * LocalBluetoothManager provides a simplified interface on top of a subset of
  * the Bluetooth API. Note that {@link #getInstance} will return null
@@ -34,7 +36,7 @@
     private final Context mContext;
 
     /** If a BT-related activity is in the foreground, this will be it. */
-    private Context mForegroundActivity;
+    private WeakReference<Context> mForegroundActivity;
 
     private final LocalBluetoothAdapter mLocalAdapter;
 
@@ -85,17 +87,19 @@
     }
 
     public Context getForegroundActivity() {
-        return mForegroundActivity;
+        return mForegroundActivity == null
+                ? null
+                : mForegroundActivity.get();
     }
 
     public boolean isForegroundActivity() {
-        return mForegroundActivity != null;
+        return mForegroundActivity != null && mForegroundActivity.get() != null;
     }
 
     public synchronized void setForegroundActivity(Context context) {
         if (context != null) {
             Log.d(TAG, "setting foreground activity to non-null context");
-            mForegroundActivity = context;
+            mForegroundActivity = new WeakReference<>(context);
         } else {
             if (mForegroundActivity != null) {
                 Log.d(TAG, "setting foreground activity to null");
diff --git a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
index 988060e..e5d97c9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/dream/DreamBackend.java
@@ -36,12 +36,12 @@
 import android.util.Log;
 import android.util.Xml;
 
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -97,15 +97,15 @@
     }
 
     public DreamBackend(Context context) {
-        mContext = context;
+        mContext = context.getApplicationContext();
         mDreamManager = IDreamManager.Stub.asInterface(
                 ServiceManager.getService(DreamService.DREAM_SERVICE));
         mComparator = new DreamInfoComparator(getDefaultDream());
-        mDreamsEnabledByDefault = context.getResources()
+        mDreamsEnabledByDefault = mContext.getResources()
                 .getBoolean(com.android.internal.R.bool.config_dreamsEnabledByDefault);
-        mDreamsActivatedOnSleepByDefault = context.getResources()
+        mDreamsActivatedOnSleepByDefault = mContext.getResources()
                 .getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
-        mDreamsActivatedOnDockByDefault = context.getResources()
+        mDreamsActivatedOnDockByDefault = mContext.getResources()
                 .getBoolean(com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
     }
 
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 61f7fe8..bf4374a 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -43,7 +43,7 @@
     boolean isAvailable();
     void setTileSpec(String tileSpec);
 
-    void clearState();
+    @Deprecated default void clearState() {}
     void refreshState();
 
     void addCallback(Callback callback);
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3c84e5a..7d90e02 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -939,9 +939,9 @@
     <dimen name="bottom_padding">48dp</dimen>
     <dimen name="edge_margin">8dp</dimen>
 
-    <dimen name="rounded_corner_radius">0dp</dimen>
-    <dimen name="rounded_corner_radius_top">0dp</dimen>
-    <dimen name="rounded_corner_radius_bottom">0dp</dimen>
+    <dimen name="rounded_corner_radius">@*android:dimen/rounded_corner_radius</dimen>
+    <dimen name="rounded_corner_radius_top">@*android:dimen/rounded_corner_radius_top</dimen>
+    <dimen name="rounded_corner_radius_bottom">@*android:dimen/rounded_corner_radius_bottom</dimen>
     <dimen name="rounded_corner_content_padding">0dp</dimen>
     <dimen name="nav_content_padding">0dp</dimen>
     <dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index b1a247a..ff383dd 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -15,7 +15,6 @@
  */
 package com.android.keyguard;
 
-import android.R.style;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.admin.DevicePolicyManager;
@@ -26,7 +25,6 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.StatsLog;
-import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
@@ -210,7 +208,7 @@
 
         if (messageId != 0) {
             final String message = mContext.getString(messageId,
-                    KeyguardUpdateMonitor.getInstance(mContext).getFailedUnlockAttempts(userId),
+                    mLockPatternUtils.getCurrentFailedPasswordAttempts(userId),
                     timeoutInSeconds);
             showDialog(null, message);
         }
@@ -255,8 +253,8 @@
     }
 
     private void reportFailedUnlockAttempt(int userId, int timeoutMs) {
-        final KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
-        final int failedAttempts = monitor.getFailedUnlockAttempts(userId) + 1; // +1 for this time
+        // +1 for this time
+        final int failedAttempts = mLockPatternUtils.getCurrentFailedPasswordAttempts(userId) + 1;
 
         if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
 
@@ -290,7 +288,6 @@
                 showWipeDialog(failedAttempts, userType);
             }
         }
-        monitor.reportFailedStrongAuthUnlockAttempt(userId);
         mLockPatternUtils.reportFailedPasswordAttempt(userId);
         if (timeoutMs > 0) {
             mLockPatternUtils.reportPasswordLockout(timeoutMs, userId);
@@ -434,7 +431,6 @@
             if (success) {
                 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
                     StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS);
-                monitor.clearFailedUnlockAttempts();
                 mLockPatternUtils.reportSuccessfulPasswordAttempt(userId);
             } else {
                 StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index ef3aa42..0e21815 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -209,9 +209,6 @@
     // Battery status
     private BatteryStatus mBatteryStatus;
 
-    // Password attempts
-    private SparseIntArray mFailedAttempts = new SparseIntArray();
-
     private final StrongAuthTracker mStrongAuthTracker;
 
     private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
@@ -1800,22 +1797,10 @@
         return mDeviceProvisioned;
     }
 
-    public void clearFailedUnlockAttempts() {
-        mFailedAttempts.delete(sCurrentUser);
-    }
-
     public ServiceState getServiceState(int subId) {
         return mServiceStates.get(subId);
     }
 
-    public int getFailedUnlockAttempts(int userId) {
-        return mFailedAttempts.get(userId, 0);
-    }
-
-    public void reportFailedStrongAuthUnlockAttempt(int userId) {
-        mFailedAttempts.put(userId, getFailedUnlockAttempts(userId) + 1);
-    }
-
     public void clearFingerprintRecognized() {
         mUserFingerprintAuthenticated.clear();
         mTrustManager.clearAllFingerprints();
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 194679c..9ced14d 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -39,10 +39,13 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.hardware.display.DisplayManager;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.SystemProperties;
 import android.provider.Settings.Secure;
 import android.support.annotation.VisibleForTesting;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
 import android.view.Gravity;
@@ -57,6 +60,7 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import com.android.internal.util.Preconditions;
 import com.android.systemui.RegionInterceptingFrameLayout.RegionInterceptableView;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
@@ -74,6 +78,9 @@
  * for antialiasing and emulation purposes.
  */
 public class ScreenDecorations extends SystemUI implements Tunable {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "ScreenDecorations";
+
     public static final String SIZE = "sysui_rounded_size";
     public static final String PADDING = "sysui_rounded_content_padding";
     private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
@@ -82,9 +89,9 @@
     private DisplayManager mDisplayManager;
     private DisplayManager.DisplayListener mDisplayListener;
 
-    private int mRoundedDefault;
-    private int mRoundedDefaultTop;
-    private int mRoundedDefaultBottom;
+    @VisibleForTesting protected int mRoundedDefault;
+    @VisibleForTesting protected int mRoundedDefaultTop;
+    @VisibleForTesting protected int mRoundedDefaultBottom;
     private View mOverlay;
     private View mBottomOverlay;
     private float mDensity;
@@ -93,26 +100,30 @@
     private DisplayCutoutView mCutoutTop;
     private DisplayCutoutView mCutoutBottom;
     private boolean mPendingRotationChange;
+    private Handler mHandler;
 
     @Override
     public void start() {
+        mHandler = startHandlerThread();
+        mHandler.post(this::startOnScreenDecorationsThread);
+        setupStatusBarPaddingIfNeeded();
+    }
+
+    @VisibleForTesting
+    Handler startHandlerThread() {
+        HandlerThread thread = new HandlerThread("ScreenDecorations");
+        thread.start();
+        return thread.getThreadHandler();
+    }
+
+    private void startOnScreenDecorationsThread() {
+        mRotation = RotationUtils.getExactRotation(mContext);
         mWindowManager = mContext.getSystemService(WindowManager.class);
-        mRoundedDefault = mContext.getResources().getDimensionPixelSize(
-                R.dimen.rounded_corner_radius);
-        mRoundedDefaultTop = mContext.getResources().getDimensionPixelSize(
-                R.dimen.rounded_corner_radius_top);
-        mRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize(
-                R.dimen.rounded_corner_radius_bottom);
+        updateRoundedCornerRadii();
         if (hasRoundedCorners() || shouldDrawCutout()) {
             setupDecorations();
         }
 
-        int padding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.rounded_corner_content_padding);
-        if (padding != 0) {
-            setupPadding(padding);
-        }
-
         mDisplayListener = new DisplayManager.DisplayListener() {
             @Override
             public void onDisplayAdded(int displayId) {
@@ -126,8 +137,8 @@
 
             @Override
             public void onDisplayChanged(int displayId) {
-                if (mOverlay != null && mBottomOverlay != null
-                        && mRotation != RotationUtils.getExactRotation(mContext)) {
+                final int newRotation = RotationUtils.getExactRotation(mContext);
+                if (mOverlay != null && mBottomOverlay != null && mRotation != newRotation) {
                     // We cannot immediately update the orientation. Otherwise
                     // WindowManager is still deferring layout until it has finished dispatching
                     // the config changes, which may cause divergence between what we draw
@@ -136,20 +147,24 @@
                     // - we are trying to redraw. This because WM resized our window and told us to.
                     // - the config change has been dispatched, so WM is no longer deferring layout.
                     mPendingRotationChange = true;
-                    mOverlay.getViewTreeObserver().addOnPreDrawListener(
-                            new RestartingPreDrawListener(mOverlay));
-                    mBottomOverlay.getViewTreeObserver().addOnPreDrawListener(
-                            new RestartingPreDrawListener(mBottomOverlay));
+                    if (DEBUG) {
+                        Log.i(TAG, "Rotation changed, deferring " + newRotation + ", staying at "
+                                + mRotation);
+                    }
 
+                    mOverlay.getViewTreeObserver().addOnPreDrawListener(
+                            new RestartingPreDrawListener(mOverlay, newRotation));
+                    mBottomOverlay.getViewTreeObserver().addOnPreDrawListener(
+                            new RestartingPreDrawListener(mBottomOverlay, newRotation));
                 }
                 updateOrientation();
             }
         };
 
-        mRotation = -1;
         mDisplayManager = (DisplayManager) mContext.getSystemService(
                 Context.DISPLAY_SERVICE);
-        mDisplayManager.registerDisplayListener(mDisplayListener, null);
+        mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);
+        updateOrientation();
     }
 
     private void setupDecorations() {
@@ -179,10 +194,11 @@
         mWindowManager.getDefaultDisplay().getMetrics(metrics);
         mDensity = metrics.density;
 
-        Dependency.get(TunerService.class).addTunable(this, SIZE);
+        Dependency.get(Dependency.MAIN_HANDLER).post(
+                () -> Dependency.get(TunerService.class).addTunable(this, SIZE));
 
         // Watch color inversion and invert the overlay as needed.
-        SecureSetting setting = new SecureSetting(mContext, Dependency.get(Dependency.MAIN_HANDLER),
+        SecureSetting setting = new SecureSetting(mContext, mHandler,
                 Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED) {
             @Override
             protected void handleValueChanged(int value, boolean observedChange) {
@@ -215,18 +231,38 @@
                         .start();
             }
         });
+
+        mOverlay.getViewTreeObserver().addOnPreDrawListener(
+                new ValidatingPreDrawListener(mOverlay));
+        mBottomOverlay.getViewTreeObserver().addOnPreDrawListener(
+                new ValidatingPreDrawListener(mBottomOverlay));
     }
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
-        mPendingRotationChange = false;
-        updateOrientation();
-        if (shouldDrawCutout() && mOverlay == null) {
-            setupDecorations();
-        }
+        mHandler.post(() -> {
+            int oldRotation = mRotation;
+            mPendingRotationChange = false;
+            updateOrientation();
+            updateRoundedCornerRadii();
+            if (DEBUG) Log.i(TAG, "onConfigChanged from rot " + oldRotation + " to " + mRotation);
+            if (shouldDrawCutout() && mOverlay == null) {
+                setupDecorations();
+            }
+            if (mOverlay != null) {
+                // Updating the layout params ensures that ViewRootImpl will call relayoutWindow(),
+                // which ensures that the forced seamless rotation will end, even if we updated
+                // the rotation before window manager was ready (and was still waiting for sending
+                // the updated rotation).
+                updateLayoutParams();
+            }
+        });
     }
 
-    protected void updateOrientation() {
+    private void updateOrientation() {
+        Preconditions.checkState(mHandler.getLooper().getThread() == Thread.currentThread(),
+                "must call on " + mHandler.getLooper().getThread()
+                        + ", but was " + Thread.currentThread());
         if (mPendingRotationChange) {
             return;
         }
@@ -241,6 +277,26 @@
         }
     }
 
+    private void updateRoundedCornerRadii() {
+        final int newRoundedDefault = mContext.getResources().getDimensionPixelSize(
+                R.dimen.rounded_corner_radius);
+        final int newRoundedDefaultTop = mContext.getResources().getDimensionPixelSize(
+                R.dimen.rounded_corner_radius_top);
+        final int newRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize(
+                R.dimen.rounded_corner_radius_bottom);
+
+        final boolean roundedCornersChanged = mRoundedDefault != newRoundedDefault
+                || mRoundedDefaultBottom != newRoundedDefaultBottom
+                || mRoundedDefaultTop != newRoundedDefaultTop;
+
+        if (roundedCornersChanged) {
+            mRoundedDefault = newRoundedDefault;
+            mRoundedDefaultTop = newRoundedDefaultTop;
+            mRoundedDefaultBottom = newRoundedDefaultBottom;
+            onTuningChanged(SIZE, null);
+        }
+    }
+
     private void updateViews() {
         View topLeft = mOverlay.findViewById(R.id.left);
         View topRight = mOverlay.findViewById(R.id.right);
@@ -306,7 +362,19 @@
                 com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout);
     }
 
-    private void setupPadding(int padding) {
+
+    private void setupStatusBarPaddingIfNeeded() {
+        // TODO: This should be moved to a more appropriate place, as it is not related to the
+        // screen decorations overlay.
+        int padding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.rounded_corner_content_padding);
+        if (padding != 0) {
+            setupStatusBarPadding(padding);
+        }
+
+    }
+
+    private void setupStatusBarPadding(int padding) {
         // Add some padding to all the content near the edge of the screen.
         StatusBar sb = getComponent(StatusBar.class);
         View statusBar = (sb != null ? sb.getStatusBarWindow() : null);
@@ -375,30 +443,32 @@
 
     @Override
     public void onTuningChanged(String key, String newValue) {
-        if (mOverlay == null) return;
-        if (SIZE.equals(key)) {
-            int size = mRoundedDefault;
-            int sizeTop = mRoundedDefaultTop;
-            int sizeBottom = mRoundedDefaultBottom;
-            if (newValue != null) {
-                try {
-                    size = (int) (Integer.parseInt(newValue) * mDensity);
-                } catch (Exception e) {
+        mHandler.post(() -> {
+            if (mOverlay == null) return;
+            if (SIZE.equals(key)) {
+                int size = mRoundedDefault;
+                int sizeTop = mRoundedDefaultTop;
+                int sizeBottom = mRoundedDefaultBottom;
+                if (newValue != null) {
+                    try {
+                        size = (int) (Integer.parseInt(newValue) * mDensity);
+                    } catch (Exception e) {
+                    }
                 }
-            }
 
-            if (sizeTop == 0) {
-                sizeTop = size;
-            }
-            if (sizeBottom == 0) {
-                sizeBottom = size;
-            }
+                if (sizeTop == 0) {
+                    sizeTop = size;
+                }
+                if (sizeBottom == 0) {
+                    sizeBottom = size;
+                }
 
-            setSize(mOverlay.findViewById(R.id.left), sizeTop);
-            setSize(mOverlay.findViewById(R.id.right), sizeTop);
-            setSize(mBottomOverlay.findViewById(R.id.left), sizeBottom);
-            setSize(mBottomOverlay.findViewById(R.id.right), sizeBottom);
-        }
+                setSize(mOverlay.findViewById(R.id.left), sizeTop);
+                setSize(mOverlay.findViewById(R.id.right), sizeTop);
+                setSize(mBottomOverlay.findViewById(R.id.left), sizeBottom);
+                setSize(mBottomOverlay.findViewById(R.id.right), sizeBottom);
+            }
+        });
     }
 
     private void setSize(View view, int pixelSize) {
@@ -457,6 +527,11 @@
             mVisibilityChangedListener = visibilityChangedListener;
             mDecorations = decorations;
             setId(R.id.display_cutout);
+            if (DEBUG) {
+                getViewTreeObserver().addOnDrawListener(() -> Log.i(TAG,
+                        (mInitialStart ? "OverlayTop" : "OverlayBottom")
+                                + " drawn in rot " + mRotation));
+            }
         }
 
         public void setColor(int color) {
@@ -692,20 +767,66 @@
     private class RestartingPreDrawListener implements ViewTreeObserver.OnPreDrawListener {
 
         private final View mView;
+        private final int mTargetRotation;
 
-        private RestartingPreDrawListener(View view) {
+        private RestartingPreDrawListener(View view, int targetRotation) {
+            mView = view;
+            mTargetRotation = targetRotation;
+        }
+
+        @Override
+        public boolean onPreDraw() {
+            mView.getViewTreeObserver().removeOnPreDrawListener(this);
+
+            if (mTargetRotation == mRotation) {
+                if (DEBUG) {
+                    Log.i(TAG, (mView == mOverlay ? "OverlayTop" : "OverlayBottom")
+                            + " already in target rot "
+                            + mTargetRotation + ", allow draw without restarting it");
+                }
+                return true;
+            }
+
+            mPendingRotationChange = false;
+            // This changes the window attributes - we need to restart the traversal for them to
+            // take effect.
+            updateOrientation();
+            if (DEBUG) {
+                Log.i(TAG, (mView == mOverlay ? "OverlayTop" : "OverlayBottom")
+                        + " restarting listener fired, restarting draw for rot " + mRotation);
+            }
+            mView.invalidate();
+            return false;
+        }
+    }
+
+    /**
+     * A pre-draw listener, that validates that the rotation we draw in matches the displays
+     * rotation before continuing the draw.
+     *
+     * This is to prevent a race condition, where we have not received the display changed event
+     * yet, and would thus draw in an old orientation.
+     */
+    private class ValidatingPreDrawListener implements ViewTreeObserver.OnPreDrawListener {
+
+        private final View mView;
+
+        public ValidatingPreDrawListener(View view) {
             mView = view;
         }
 
         @Override
         public boolean onPreDraw() {
-            mPendingRotationChange = false;
-            mView.getViewTreeObserver().removeOnPreDrawListener(this);
-            // This changes the window attributes - we need to restart the traversal for them to
-            // take effect.
-            updateOrientation();
-            mView.invalidate();
-            return false;
+            final int displayRotation = RotationUtils.getExactRotation(mContext);
+            if (displayRotation != mRotation && !mPendingRotationChange) {
+                if (DEBUG) {
+                    Log.i(TAG, "Drawing rot " + mRotation + ", but display is at rot "
+                            + displayRotation + ". Restarting draw");
+                }
+                mView.invalidate();
+                return false;
+            }
+            return true;
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 89688fb..33db2c8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1647,7 +1647,6 @@
             resetKeyguardDonePendingLocked();
         }
 
-        mUpdateMonitor.clearFailedUnlockAttempts();
         mUpdateMonitor.clearFingerprintRecognized();
 
         if (mGoingToSleep) {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 065e9cc..288f058 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -266,9 +266,12 @@
                 || mEstimate.estimateMillis < mSevereWarningThreshold) {
             nb.setColor(Utils.getColorAttr(mContext, android.R.attr.colorError));
         }
-        nb.addAction(0,
-                mContext.getString(R.string.battery_saver_start_action),
-                pendingBroadcast(ACTION_START_SAVER));
+
+        if (!mPowerMan.isPowerSaveMode()) {
+            nb.addAction(0,
+                    mContext.getString(R.string.battery_saver_start_action),
+                    pendingBroadcast(ACTION_START_SAVER));
+        }
         nb.setOnlyAlertOnce(!mPlaySound);
         mPlaySound = false;
         SystemUI.overrideNotificationAppName(mContext, nb, false);
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 9a648d1..0b9067e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -333,10 +333,11 @@
     @VisibleForTesting
     boolean shouldDismissLowBatteryWarning(boolean plugged, int oldBucket, int bucket,
             long timeRemaining, boolean isPowerSaver) {
-        final boolean hybridWouldDismiss = mEnhancedEstimates.isHybridNotificationEnabled()
+        final boolean hybridEnabled = mEnhancedEstimates.isHybridNotificationEnabled();
+        final boolean hybridWouldDismiss = hybridEnabled
                 && timeRemaining > mEnhancedEstimates.getLowWarningThreshold();
         final boolean standardWouldDismiss = (bucket > oldBucket && bucket > 0);
-        return isPowerSaver
+        return (isPowerSaver && !hybridEnabled)
                 || plugged
                 || (standardWouldDismiss && (!mEnhancedEstimates.isHybridNotificationEnabled()
                         || hybridWouldDismiss));
@@ -344,14 +345,14 @@
 
     private boolean isEnhancedTrigger(boolean plugged, long timeRemaining, boolean isPowerSaver,
             int batteryStatus) {
-        if (plugged || isPowerSaver || batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
+        if (plugged || batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
             return false;
         }
         int warnLevel = mLowBatteryReminderLevels[0];
         int critLevel = mLowBatteryReminderLevels[1];
 
-        // Only show the low warning once per charge cycle
-        final boolean canShowWarning = !mLowWarningShownThisChargeCycle
+        // Only show the low warning once per charge cycle & no battery saver
+        final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !isPowerSaver
                 && (timeRemaining < mEnhancedEstimates.getLowWarningThreshold()
                         || mBatteryLevel <= warnLevel);
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 0876a5d..3fc258b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -285,9 +285,6 @@
 
         updatePageIndicator();
 
-        for (TileRecord r : mRecords) {
-            r.tile.clearState();
-        }
         if (mListening) {
             refreshAllTiles();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 53a576d..591e9e0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -95,7 +95,6 @@
                 continue;
             }
             tile.setListening(this, true);
-            tile.clearState();
             tile.refreshState();
             tile.setListening(this, false);
             tile.setTileSpec(spec);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 834feb7..022a2b4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -211,10 +211,6 @@
         mHandler.obtainMessage(H.REFRESH_STATE, arg).sendToTarget();
     }
 
-    public void clearState() {
-        mHandler.sendEmptyMessage(H.CLEAR_STATE);
-    }
-
     public void userSwitch(int newUserId) {
         mHandler.obtainMessage(H.USER_SWITCH, newUserId, 0).sendToTarget();
     }
@@ -266,11 +262,6 @@
 
     public abstract Intent getLongClickIntent();
 
-    protected void handleClearState() {
-        mTmpState = newTileState();
-        mState = newTileState();
-    }
-
     protected void handleRefreshState(Object arg) {
         handleUpdateState(mTmpState, arg);
         final boolean changed = mTmpState.copyTo(mState);
@@ -409,11 +400,10 @@
         private static final int TOGGLE_STATE_CHANGED = 8;
         private static final int SCAN_STATE_CHANGED = 9;
         private static final int DESTROY = 10;
-        private static final int CLEAR_STATE = 11;
-        private static final int REMOVE_CALLBACKS = 12;
-        private static final int REMOVE_CALLBACK = 13;
-        private static final int SET_LISTENING = 14;
-        private static final int STALE = 15;
+        private static final int REMOVE_CALLBACKS = 11;
+        private static final int REMOVE_CALLBACK = 12;
+        private static final int SET_LISTENING = 13;
+        private static final int STALE = 14;
 
         @VisibleForTesting
         protected H(Looper looper) {
@@ -467,9 +457,6 @@
                 } else if (msg.what == DESTROY) {
                     name = "handleDestroy";
                     handleDestroy();
-                } else if (msg.what == CLEAR_STATE) {
-                    name = "handleClearState";
-                    handleClearState();
                 } else if (msg.what == SET_LISTENING) {
                     name = "handleSetListeningInternal";
                     handleSetListeningInternal(msg.obj, msg.arg1 != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
index 06f26c9..469c3c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java
@@ -667,9 +667,15 @@
                     entry.row.getNotificationChildren();
             for (int i = 0; i < notificationChildren.size(); i++) {
                 ExpandableNotificationRow row = notificationChildren.get(i);
-                if ((row.getStatusBarNotification().getNotification().flags
-                        & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
-                    // the child is a foreground service notification which we can't remove!
+                NotificationData.Entry childEntry = row.getEntry();
+                boolean isForeground = (row.getStatusBarNotification().getNotification().flags
+                        & Notification.FLAG_FOREGROUND_SERVICE) != 0;
+                boolean keepForReply = FORCE_REMOTE_INPUT_HISTORY
+                        && (shouldKeepForRemoteInput(childEntry)
+                                || shouldKeepForSmartReply(childEntry));
+                if (isForeground || keepForReply) {
+                    // the child is a foreground service notification which we can't remove or it's
+                    // a child we're keeping around for reply!
                     continue;
                 }
                 row.setKeepInParent(true);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index af1d220..48ffe81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -189,7 +189,7 @@
                 mNavigationBarView.getDownHitTarget() == HIT_TARGET_DEAD_ZONE;
         if (mOverviewEventSender.getProxy() == null || (!mNavigationBarView.isQuickScrubEnabled()
                 && !mNavigationBarView.isQuickStepSwipeUpEnabled())) {
-            return false;
+            return deadZoneConsumed;
         }
         mNavigationBarView.requestUnbufferedDispatch(event);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index f1bf31d..cc96917 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -21,6 +21,7 @@
 
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyString;
@@ -34,8 +35,10 @@
 
 import android.app.Fragment;
 import android.content.res.Configuration;
+import android.os.Handler;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 import android.view.Display;
 import android.view.View;
@@ -60,6 +63,7 @@
 @SmallTest
 public class ScreenDecorationsTest extends SysuiTestCase {
 
+    private TestableLooper mTestableLooper;
     private ScreenDecorations mScreenDecorations;
     private StatusBar mStatusBar;
     private WindowManager mWindowManager;
@@ -71,6 +75,10 @@
 
     @Before
     public void setup() {
+        mTestableLooper = TestableLooper.get(this);
+        mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
+                new Handler(mTestableLooper.getLooper()));
+
         mStatusBar = mock(StatusBar.class);
         mWindowManager = mock(WindowManager.class);
         mView = spy(new StatusBarWindowView(mContext, null));
@@ -88,7 +96,31 @@
 
         mTunerService = mDependency.injectMockDependency(TunerService.class);
 
-        mScreenDecorations = new ScreenDecorations();
+
+        mScreenDecorations = new ScreenDecorations() {
+            @Override
+            public void start() {
+                super.start();
+                mTestableLooper.processAllMessages();
+            }
+
+            @Override
+            Handler startHandlerThread() {
+                return new Handler(mTestableLooper.getLooper());
+            }
+
+            @Override
+            protected void onConfigurationChanged(Configuration newConfig) {
+                super.onConfigurationChanged(newConfig);
+                mTestableLooper.processAllMessages();
+            }
+
+            @Override
+            public void onTuningChanged(String key, String newValue) {
+                super.onTuningChanged(key, newValue);
+                mTestableLooper.processAllMessages();
+            }
+        };
         mScreenDecorations.mContext = mContext;
         mScreenDecorations.mComponents = mContext.getComponents();
 
@@ -195,4 +227,17 @@
         verify(padding).destroy();
     }
 
+    @Test
+    public void testUpdateRoundedCorners() {
+        mContext.getOrCreateTestableResources().addOverride(
+                com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
+        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 20);
+
+        mScreenDecorations.start();
+        assertEquals(mScreenDecorations.mRoundedDefault, 20);
+
+        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 5);
+        mScreenDecorations.onConfigurationChanged(null);
+        assertEquals(mScreenDecorations.mRoundedDefault, 5);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index 5ecf0c0..a9d49f9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -323,9 +323,9 @@
     }
 
     @Test
-    public void testShouldDismissLowBatteryWarning_dismissWhenPowerSaverEnabled() {
+    public void testShouldDismissLowBatteryWarning_dismissWhenPowerSaverEnabledLegacy() {
         mPowerUI.start();
-        when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(false);
         when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
         when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
 
@@ -337,6 +337,20 @@
     }
 
     @Test
+    public void testShouldNotDismissLowBatteryWarning_dismissWhenPowerSaverEnabledHybrid() {
+        mPowerUI.start();
+        when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
+        when(mEnhancedEstimates.getLowWarningThreshold()).thenReturn(PowerUI.THREE_HOURS_IN_MILLIS);
+        when(mEnhancedEstimates.getSevereWarningThreshold()).thenReturn(ONE_HOUR_MILLIS);
+
+        // device that gets power saver turned on should dismiss
+        boolean shouldDismiss =
+            mPowerUI.shouldDismissLowBatteryWarning(UNPLUGGED, BELOW_WARNING_BUCKET,
+                BELOW_WARNING_BUCKET, ABOVE_HYBRID_THRESHOLD, !POWER_SAVER_OFF);
+        assertFalse(shouldDismiss);
+    }
+
+    @Test
     public void testShouldDismissLowBatteryWarning_dismissWhenPlugged() {
         mPowerUI.start();
         when(mEnhancedEstimates.isHybridNotificationEnabled()).thenReturn(true);
diff --git a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml
index 754ba72..b08924b 100644
--- a/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationCornerOverlay/res/values/strings.xml
@@ -16,7 +16,7 @@
   -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <string name="display_cutout_emulation_overlay">Corner display cutout</string>
+    <string name="display_cutout_emulation_overlay">Corner cutout</string>
 
 </resources>
 
diff --git a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml
index 68c2dcb..0a106fa 100644
--- a/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationDoubleOverlay/res/values/strings.xml
@@ -16,7 +16,7 @@
   -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <string name="display_cutout_emulation_overlay">Double display cutout</string>
+    <string name="display_cutout_emulation_overlay">Double cutout</string>
 
 </resources>
 
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml
index 4989677..0bf8330 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/strings.xml
@@ -18,7 +18,7 @@
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <string name="display_cutout_emulation_overlay">Narrow display cutout</string>
+    <string name="display_cutout_emulation_overlay">Narrow cutout</string>
 
 </resources>
 
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml
index 6dcbbd9..bcc7c97 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/strings.xml
@@ -16,7 +16,7 @@
   -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <string name="display_cutout_emulation_overlay">Tall display cutout</string>
+    <string name="display_cutout_emulation_overlay">Tall cutout</string>
 
 </resources>
 
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml
index f4b9f7e..0fcbdebb 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/strings.xml
@@ -16,7 +16,7 @@
   -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
 
-    <string name="display_cutout_emulation_overlay">Wide display cutout</string>
+    <string name="display_cutout_emulation_overlay">Wide cutout</string>
 
 </resources>
 
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
index c9c7adc..f69b638 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java
@@ -48,11 +48,6 @@
     }
 
     @Override
-    public void onUnlockUser(int userHandle) {
-        FgThread.getHandler().post(() -> mImpl.onUserUnlocked(userHandle));
-    }
-
-    @Override
     public void onStopUser(int userHandle) {
         mImpl.onUserStopped(userHandle);
     }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index db8ad12..b71d7a7 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -19,7 +19,6 @@
 import static android.content.Context.KEYGUARD_SERVICE;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.annotation.UserIdInt;
@@ -2697,7 +2696,12 @@
         }
     }
 
-    void onUserUnlocked(int userId) {
+    /**
+     * This does not use the usual onUserUnlocked() listener mechanism because it is
+     * invoked at a choreographed point in the middle of the user unlock sequence,
+     * before the boot-completed broadcast is issued and the listeners notified.
+     */
+    void handleUserUnlocked(int userId) {
         if (isProfileWithLockedParent(userId)) {
             return;
         }
@@ -2734,7 +2738,7 @@
                 }
             }
         }
-        Slog.i(TAG, "Async processing of onUserUnlocked u" + userId + " took "
+        Slog.i(TAG, "Processing of handleUserUnlocked u" + userId + " took "
                 + (SystemClock.elapsedRealtime() - time) + " ms");
     }
 
@@ -4801,5 +4805,11 @@
                 return widgetPackages;
             }
         }
+
+        @Override
+        public void unlockUser(int userId) {
+            handleUserUnlocked(userId);
+        }
+
     }
 }
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index dc84498..5882303 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -81,6 +81,13 @@
         void onDestroy();
     }
 
+    /**
+     * Wrapper that guarantees that only one callback is triggered by ignoring further calls after
+     * it's destroyed.
+     *
+     * <p>It's needed becase {@link #onCancel(IntentSender)} is always called when the Save UI
+     * dialog is dismissed.
+     */
     private class OneTimeListener implements OnSaveListener {
 
         private final OnSaveListener mRealListener;
@@ -96,7 +103,6 @@
             if (mDone) {
                 return;
             }
-            mDone = true;
             mRealListener.onSave();
         }
 
@@ -106,7 +112,6 @@
             if (mDone) {
                 return;
             }
-            mDone = true;
             mRealListener.onCancel(listener);
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2861600..444ad8e 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -26870,6 +26870,18 @@
                 return ActivityManagerService.this.getHomeIntent();
             }
         }
+
+        @Override
+        public void notifyDefaultDisplaySizeChanged() {
+            synchronized (this) {
+                if (mSystemServiceManager.isBootCompleted() && mHomeProcess != null) {
+
+                    // TODO: Ugly hack to unblock the release
+                    Slog.i(TAG, "Killing home process because of display size change");
+                    removeProcessLocked(mHomeProcess, false, true, "kill home screen size");
+                }
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index dc9a5adb..093bd87 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2844,6 +2844,7 @@
             pw.println("  --checkin: output checkin format, resetting data.");
             pw.println("  --C: output checkin format, not resetting data.");
             pw.println("  --proto: output dump in protocol buffer format.");
+            pw.println("  --autofill: dump just the autofill-related state of an activity");
         } else {
             pw.println("Activity manager (activity) commands:");
             pw.println("  help");
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 75f2723..60f79f72 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -694,9 +694,13 @@
         final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null;
         if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) {
             // Picture-in-picture mode changes also trigger a multi-window mode change as well, so
-            // update that here in order
+            // update that here in order. Set the last reported MW state to the same as the PiP
+            // state since we haven't yet actually resized the task (these callbacks need to
+            // preceed the configuration change from the resiez.
+            // TODO(110009072): Once we move these callbacks to the client, remove all logic related
+            // to forcing the update of the picture-in-picture mode as a part of the PiP animation.
             mLastReportedPictureInPictureMode = inPictureInPictureMode;
-            mLastReportedMultiWindowMode = inMultiWindowMode();
+            mLastReportedMultiWindowMode = inPictureInPictureMode;
             final Configuration newConfig = task.computeNewOverrideConfigurationForBounds(
                     targetStackBounds, null);
             schedulePictureInPictureModeChanged(newConfig);
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 18c0957..415a822 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -24,7 +24,6 @@
 import static android.app.ActivityManager.USER_OP_SUCCESS;
 import static android.os.Process.SHELL_UID;
 import static android.os.Process.SYSTEM_UID;
-
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -48,6 +47,7 @@
 import android.app.IUserSwitchObserver;
 import android.app.KeyguardManager;
 import android.app.usage.UsageEvents;
+import android.appwidget.AppWidgetManagerInternal;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.Intent;
@@ -87,8 +87,8 @@
 import android.util.SparseIntArray;
 import android.util.TimingsTraceLog;
 import android.util.proto.ProtoOutputStream;
-
 import android.view.Window;
+
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -533,6 +533,9 @@
             }
         }
 
+        // Spin up app widgets prior to boot-complete, so they can be ready promptly
+        mInjector.startUserWidgets(userId);
+
         Slog.i(TAG, "Sending BOOT_COMPLETE user #" + userId);
         // Do not report secondary users, runtime restarts or first boot/upgrade
         if (userId == UserHandle.USER_SYSTEM
@@ -2173,6 +2176,13 @@
             }
         }
 
+        void startUserWidgets(int userId) {
+            AppWidgetManagerInternal awm = LocalServices.getService(AppWidgetManagerInternal.class);
+            if (awm != null) {
+                awm.unlockUser(userId);
+            }
+        }
+
         void updateUserConfiguration() {
             synchronized (mService) {
                 mService.updateUserConfigurationLocked();
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 349e1c8..512e851 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -104,6 +104,12 @@
     public static final int FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 10;
 
     /**
+     * Flag: The display cutout of this display is masked.
+     * @hide
+     */
+    public static final int FLAG_MASK_DISPLAY_CUTOUT = 1 << 11;
+
+    /**
      * Touch attachment: Display does not receive touch.
      */
     public static final int TOUCH_NONE = 0;
@@ -453,6 +459,9 @@
         if ((flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
             msg.append(", FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD");
         }
+        if ((flags & FLAG_MASK_DISPLAY_CUTOUT) != 0) {
+            msg.append(", FLAG_MASK_DISPLAY_CUTOUT");
+        }
         return msg.toString();
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index ddd8855..cc5a827 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -151,6 +151,8 @@
     // Otherwise WFD is enabled according to the value of config_enableWifiDisplay.
     private static final String FORCE_WIFI_DISPLAY_ENABLE = "persist.debug.wfd.enable";
 
+    private static final String PROP_DEFAULT_DISPLAY_TOP_INSET = "persist.sys.displayinset.top";
+
     private static final long WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT = 10000;
 
     private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;
@@ -243,6 +245,15 @@
     // device).
     private Point mStableDisplaySize = new Point();
 
+    // Whether the system has finished booting or not.
+    private boolean mSystemReady;
+
+    // The top inset of the default display.
+    // This gets persisted so that the boot animation knows how to transition from the display's
+    // full size to the size configured by the user. Right now we only persist and animate the top
+    // inset, but theoretically we could do it for all of them.
+    private int mDefaultDisplayTopInset;
+
     // Viewports of the default display and the display that should receive touch
     // input from an external source.  Used by the input system.
     private final DisplayViewport mDefaultViewport = new DisplayViewport();
@@ -301,6 +312,7 @@
         Resources resources = mContext.getResources();
         mDefaultDisplayDefaultColorMode = mContext.getResources().getInteger(
                 com.android.internal.R.integer.config_defaultDisplayDefaultColorMode);
+        mDefaultDisplayTopInset = SystemProperties.getInt(PROP_DEFAULT_DISPLAY_TOP_INSET, -1);
         float[] lux = getFloatArray(resources.obtainTypedArray(
                 com.android.internal.R.array.config_minimumBrightnessCurveLux));
         float[] nits = getFloatArray(resources.obtainTypedArray(
@@ -311,6 +323,8 @@
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();
         mCurrentUserId = UserHandle.USER_SYSTEM;
+
+        mSystemReady = false;
     }
 
     public void setupSchedulerPolicies() {
@@ -400,6 +414,10 @@
         synchronized (mSyncRoot) {
             mSafeMode = safeMode;
             mOnlyCore = onlyCore;
+            mSystemReady = true;
+            // Just in case the top inset changed before the system was ready. At this point, any
+            // relevant configuration should be in place.
+            recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY));
         }
 
         mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
@@ -457,7 +475,7 @@
             LogicalDisplay display = mLogicalDisplays.get(displayId);
             if (display != null) {
                 if (display.setDisplayInfoOverrideFromWindowManagerLocked(info)) {
-                    sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+                    handleLogicalDisplayChanged(displayId, display);
                     scheduleTraversalLocked(false);
                 }
             }
@@ -938,6 +956,13 @@
         scheduleTraversalLocked(false);
     }
 
+    private void handleLogicalDisplayChanged(int displayId, @NonNull LogicalDisplay display) {
+        if (displayId == Display.DEFAULT_DISPLAY) {
+            recordTopInsetLocked(display);
+        }
+        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+    }
+
     private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) {
         final int count = mDisplayDevices.size();
         for (int i = 0; i < count; i++) {
@@ -991,6 +1016,7 @@
         configureColorModeLocked(display, device);
         if (isDefault) {
             recordStableDisplayStatsIfNeededLocked(display);
+            recordTopInsetLocked(display);
         }
 
         mLogicalDisplays.put(displayId, display);
@@ -1039,6 +1065,21 @@
         }
     }
 
+    private void recordTopInsetLocked(@Nullable LogicalDisplay d) {
+        // We must only persist the inset after boot has completed, otherwise we will end up
+        // overwriting the persisted value before the masking flag has been loaded from the
+        // resource overlay.
+        if (!mSystemReady || d == null) {
+            return;
+        }
+        int topInset = d.getInsets().top;
+        if (topInset == mDefaultDisplayTopInset) {
+            return;
+        }
+        mDefaultDisplayTopInset = topInset;
+        SystemProperties.set(PROP_DEFAULT_DISPLAY_TOP_INSET, Integer.toString(topInset));
+    }
+
     private void setStableDisplaySizeLocked(int width, int height) {
         mStableDisplaySize = new Point(width, height);
         try {
@@ -1118,7 +1159,7 @@
                 sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
                 changed = true;
             } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
-                sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+                handleLogicalDisplayChanged(displayId, display);
                 changed = true;
             }
         }
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 21ae048..16d82df 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -402,6 +402,10 @@
                             && SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
                         mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
                     }
+                    if (res.getBoolean(
+                            com.android.internal.R.bool.config_maskMainBuiltInDisplayCutout)) {
+                        mInfo.flags |= DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT;
+                    }
                     mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
                             mInfo.width, mInfo.height);
                     mInfo.type = Display.TYPE_BUILT_IN;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 23ee56b..5b7c520 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -18,11 +18,14 @@
 
 import android.graphics.Rect;
 import android.hardware.display.DisplayManagerInternal;
+import android.os.SystemProperties;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
+import com.android.server.wm.utils.InsetUtils;
+
 import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.List;
@@ -55,6 +58,8 @@
  * </p>
  */
 final class LogicalDisplay {
+    private static final String PROP_MASKING_INSET_TOP = "persist.sys.displayinset.top";
+
     private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
 
     // The layer stack we use when the display has been blanked to prevent any
@@ -251,14 +256,18 @@
             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
                 mBaseDisplayInfo.flags |= Display.FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
             }
+            Rect maskingInsets = getMaskingInsets(deviceInfo);
+            int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right;
+            int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom;
+
             mBaseDisplayInfo.type = deviceInfo.type;
             mBaseDisplayInfo.address = deviceInfo.address;
             mBaseDisplayInfo.name = deviceInfo.name;
             mBaseDisplayInfo.uniqueId = deviceInfo.uniqueId;
-            mBaseDisplayInfo.appWidth = deviceInfo.width;
-            mBaseDisplayInfo.appHeight = deviceInfo.height;
-            mBaseDisplayInfo.logicalWidth = deviceInfo.width;
-            mBaseDisplayInfo.logicalHeight = deviceInfo.height;
+            mBaseDisplayInfo.appWidth = maskedWidth;
+            mBaseDisplayInfo.appHeight = maskedHeight;
+            mBaseDisplayInfo.logicalWidth = maskedWidth;
+            mBaseDisplayInfo.logicalHeight = maskedHeight;
             mBaseDisplayInfo.rotation = Surface.ROTATION_0;
             mBaseDisplayInfo.modeId = deviceInfo.modeId;
             mBaseDisplayInfo.defaultModeId = deviceInfo.defaultModeId;
@@ -275,13 +284,15 @@
             mBaseDisplayInfo.appVsyncOffsetNanos = deviceInfo.appVsyncOffsetNanos;
             mBaseDisplayInfo.presentationDeadlineNanos = deviceInfo.presentationDeadlineNanos;
             mBaseDisplayInfo.state = deviceInfo.state;
-            mBaseDisplayInfo.smallestNominalAppWidth = deviceInfo.width;
-            mBaseDisplayInfo.smallestNominalAppHeight = deviceInfo.height;
-            mBaseDisplayInfo.largestNominalAppWidth = deviceInfo.width;
-            mBaseDisplayInfo.largestNominalAppHeight = deviceInfo.height;
+            mBaseDisplayInfo.smallestNominalAppWidth = maskedWidth;
+            mBaseDisplayInfo.smallestNominalAppHeight = maskedHeight;
+            mBaseDisplayInfo.largestNominalAppWidth = maskedWidth;
+            mBaseDisplayInfo.largestNominalAppHeight = maskedHeight;
             mBaseDisplayInfo.ownerUid = deviceInfo.ownerUid;
             mBaseDisplayInfo.ownerPackageName = deviceInfo.ownerPackageName;
-            mBaseDisplayInfo.displayCutout = deviceInfo.displayCutout;
+            boolean maskCutout =
+                    (deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0;
+            mBaseDisplayInfo.displayCutout = maskCutout ? null : deviceInfo.displayCutout;
 
             mPrimaryDisplayDeviceInfo = deviceInfo;
             mInfo = null;
@@ -289,6 +300,29 @@
     }
 
     /**
+     * Return the insets currently applied to the display.
+     *
+     * Note that the base DisplayInfo already takes these insets into account, so if you want to
+     * find out the <b>true</b> size of the display, you need to add them back to the logical
+     * dimensions.
+     */
+    public Rect getInsets() {
+        return getMaskingInsets(mPrimaryDisplayDeviceInfo);
+    }
+
+    /**
+     * Returns insets in ROTATION_0 for areas that are masked.
+     */
+    private static Rect getMaskingInsets(DisplayDeviceInfo deviceInfo) {
+        boolean maskCutout = (deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0;
+        if (maskCutout && deviceInfo.displayCutout != null) {
+            return deviceInfo.displayCutout.getSafeInsets();
+        } else {
+            return new Rect();
+        }
+    }
+
+    /**
      * Applies the layer stack and transformation to the given display device
      * so that it shows the contents of this logical display.
      *
@@ -349,6 +383,12 @@
         int physWidth = rotated ? displayDeviceInfo.height : displayDeviceInfo.width;
         int physHeight = rotated ? displayDeviceInfo.width : displayDeviceInfo.height;
 
+        Rect maskingInsets = getMaskingInsets(displayDeviceInfo);
+        InsetUtils.rotateInsets(maskingInsets, orientation);
+        // Don't consider the masked area as available when calculating the scaling below.
+        physWidth -= maskingInsets.left + maskingInsets.right;
+        physHeight -= maskingInsets.top + maskingInsets.bottom;
+
         // Determine whether the width or height is more constrained to be scaled.
         //    physWidth / displayInfo.logicalWidth    => letter box
         // or physHeight / displayInfo.logicalHeight  => pillar box
@@ -375,6 +415,9 @@
         mTempDisplayRect.set(displayRectLeft, displayRectTop,
                 displayRectLeft + displayRectWidth, displayRectTop + displayRectHeight);
 
+        // Now add back the offset for the masked area.
+        mTempDisplayRect.offset(maskingInsets.left, maskingInsets.top);
+
         mTempDisplayRect.left += mDisplayOffsetX;
         mTempDisplayRect.right += mDisplayOffsetX;
         mTempDisplayRect.top += mDisplayOffsetY;
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index f082271..c738701 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -22,11 +22,14 @@
 import static android.content.Intent.ACTION_PACKAGE_REMOVED;
 import static android.content.Intent.ACTION_USER_ADDED;
 import static android.content.Intent.ACTION_USER_REMOVED;
+import static android.content.pm.PackageManager.GET_SHARED_LIBRARY_FILES;
+import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 import static android.content.pm.PackageManager.SIGNATURE_MATCH;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityThread;
 import android.app.IActivityManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -34,6 +37,7 @@
 import android.content.IntentFilter;
 import android.content.om.IOverlayManager;
 import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManagerInternal;
@@ -269,13 +273,30 @@
 
     @Override
     public void onBootPhase(int phase) {
-        if (phase == PHASE_SYSTEM_SERVICES_READY) {
+        if (phase == PHASE_SYSTEM_SERVICES_READY && mInitCompleteSignal != null) {
             ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
                     "Wait for OverlayManagerService init");
             mInitCompleteSignal = null;
         }
     }
 
+    public void updateSystemUiContext() {
+        if (mInitCompleteSignal != null) {
+            ConcurrentUtils.waitForFutureNoInterrupt(mInitCompleteSignal,
+                    "Wait for OverlayManagerService init");
+            mInitCompleteSignal = null;
+        }
+
+        final ApplicationInfo ai;
+        try {
+            ai = mPackageManager.mPackageManager.getApplicationInfo("android",
+                    GET_SHARED_LIBRARY_FILES, UserHandle.USER_SYSTEM);
+        } catch (RemoteException e) {
+            throw e.rethrowAsRuntimeException();
+        }
+        ActivityThread.currentActivityThread().handleSystemApplicationInfoChanged(ai);
+    }
+
     private void initIfNeeded() {
         final UserManager um = getContext().getSystemService(UserManager.class);
         final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index b2a12be..86f328d 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -31,11 +31,13 @@
 import android.os.Debug;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.view.Choreographer;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -112,6 +114,7 @@
     private final Interpolator mFastOutSlowInInterpolator;
     private boolean mFinishAnimationAfterTransition = false;
     private final AnimationHandler mAnimationHandler;
+    private Choreographer mChoreographer;
 
     private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000;
 
@@ -123,6 +126,12 @@
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_slow_in);
         mAnimationHandler = animationHandler;
+        if (animationHandler != null) {
+            // If an animation handler is provided, then ensure that it runs on the sf vsync tick
+            handler.runWithScissors(() -> mChoreographer = Choreographer.getSfInstance(),
+                    0 /* timeout */);
+            animationHandler.setProvider(new SfVsyncFrameCallbackProvider(mChoreographer));
+        }
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2887e5ef..2941e93 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1775,8 +1775,9 @@
         final int newDensity = mDisplayInfo.logicalDensityDpi;
         final DisplayCutout newCutout = mDisplayInfo.displayCutout;
 
-        final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth
-                || mInitialDisplayHeight != newHeight
+        final boolean sizeChanged = mInitialDisplayWidth != newWidth
+                || mInitialDisplayHeight != newHeight;
+        final boolean displayMetricsChanged = sizeChanged
                 || mInitialDisplayDensity != mDisplayInfo.logicalDensityDpi
                 || !Objects.equals(mInitialDisplayCutout, newCutout);
 
@@ -1798,6 +1799,10 @@
             mInitialDisplayCutout = newCutout;
             mService.reconfigureDisplayLocked(this);
         }
+
+        if (isDefaultDisplay && sizeChanged) {
+            mService.mH.post(mService.mAmInternal::notifyDefaultDisplaySizeChanged);
+        }
     }
 
     /** Sets the maximum width the screen resolution can be */
diff --git a/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
index bebc565..efb43a6 100644
--- a/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
+++ b/services/core/java/com/android/server/wm/ForcedSeamlessRotator.java
@@ -21,6 +21,7 @@
 
 import android.graphics.Matrix;
 import android.view.DisplayInfo;
+import android.view.Surface.Rotation;
 
 import com.android.server.wm.utils.CoordinateTransforms;
 
@@ -65,6 +66,16 @@
     }
 
     /**
+     * Returns the rotation of the display before it started rotating.
+     *
+     * @return the old rotation of the display
+     */
+    @Rotation
+    public int getOldRotation() {
+        return mOldRotation;
+    }
+
+    /**
      * Removes the transform to the window token's surface that undoes the effect of the global
      * display rotation.
      *
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index fa8a5c6..755a571 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -37,6 +37,7 @@
 import android.view.Surface;
 import android.view.Surface.OutOfResourcesException;
 import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -268,6 +269,12 @@
                     .setSecure(isSecure)
                     .build();
 
+            // In case display bounds change, screenshot buffer and surface may mismatch so set a
+            // scaling mode.
+            Transaction t2 = new Transaction();
+            t2.setOverrideScalingMode(mSurfaceControl, Surface.SCALING_MODE_SCALE_TO_WINDOW);
+            t2.apply(true /* sync */);
+
             // capture a screenshot into the surface we just created
             // TODO(multidisplay): we should use the proper display
             final int displayId = SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c4a0a69..8b4a2dd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1005,7 +1005,6 @@
         mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
 
         final AnimationHandler animationHandler = new AnimationHandler();
-        animationHandler.setProvider(new SfVsyncFrameCallbackProvider());
         mBoundsAnimationController = new BoundsAnimationController(context, mAppTransition,
                 AnimationThread.getHandler(), animationHandler);
 
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 009f393..1ae680f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -681,6 +681,10 @@
 
     void forceSeamlesslyRotateIfAllowed(int oldRotation, int rotation) {
         if (mForceSeamlesslyRotate) {
+            if (mPendingForcedSeamlessRotate != null) {
+                oldRotation = mPendingForcedSeamlessRotate.getOldRotation();
+            }
+
             mPendingForcedSeamlessRotate = new ForcedSeamlessRotator(
                     oldRotation, rotation, getDisplayInfo());
             mPendingForcedSeamlessRotate.unrotate(this.mToken);
diff --git a/services/core/java/com/android/server/wm/utils/InsetUtils.java b/services/core/java/com/android/server/wm/utils/InsetUtils.java
index b4a998a..c8600dd 100644
--- a/services/core/java/com/android/server/wm/utils/InsetUtils.java
+++ b/services/core/java/com/android/server/wm/utils/InsetUtils.java
@@ -17,6 +17,7 @@
 package com.android.server.wm.utils;
 
 import android.graphics.Rect;
+import android.view.Surface;
 
 /**
  * Utility methods to handle insets represented as rects.
@@ -27,6 +28,32 @@
     }
 
     /**
+     * Transforms insets given in one rotation into insets in a different rotation.
+     *
+     * @param inOutInsets the insets to transform, is set to the transformed insets
+     * @param rotationDelta the delta between the new and old rotation.
+     *                      Must be one of Surface.ROTATION_0/90/180/270.
+     */
+    public static void rotateInsets(Rect inOutInsets, int rotationDelta) {
+        final Rect r = inOutInsets;
+        switch (rotationDelta) {
+            case Surface.ROTATION_0:
+                return;
+            case Surface.ROTATION_90:
+                r.set(r.top, r.right, r.bottom, r.left);
+                break;
+            case Surface.ROTATION_180:
+                r.set(r.right, r.bottom, r.left, r.top);
+                break;
+            case Surface.ROTATION_270:
+                r.set(r.bottom, r.left, r.top, r.right);
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown rotation: " + rotationDelta);
+        }
+    }
+
+    /**
      * Adds {@code insetsToAdd} to {@code inOutInsets}.
      */
     public static void addInsets(Rect inOutInsets, Rect insetsToAdd) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b74a582..6ee7d49 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4572,10 +4572,12 @@
         enforceFullCrossUsersPermission(userHandle);
         synchronized (getLockObject()) {
             if (!isCallerWithSystemUid()) {
-                // This API can only be called by an active device admin,
-                // so try to retrieve it to check that the caller is one.
-                getActiveAdminForCallerLocked(
-                        null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+                // This API can be called by an active device admin or by keyguard code.
+                if (mContext.checkCallingPermission(permission.ACCESS_KEYGUARD_SECURE_STORAGE)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    getActiveAdminForCallerLocked(
+                            null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, parent);
+                }
             }
 
             DevicePolicyData policy = getUserDataUnchecked(getCredentialOwner(userHandle, parent));
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1880e9f..a61970e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -28,6 +28,8 @@
 import android.content.res.Configuration;
 import android.content.res.Resources.Theme;
 import android.database.sqlite.SQLiteCompatibilityWalFlags;
+import android.database.sqlite.SQLiteGlobal;
+import android.hardware.display.DisplayManagerInternal;
 import android.os.BaseBundle;
 import android.os.Binder;
 import android.os.Build;
@@ -346,6 +348,10 @@
             Binder.setWarnOnBlocking(true);
             // The system server should always load safe labels
             PackageItemInfo.setForceSafeLabels(true);
+
+            // Default to FULL within the system server.
+            SQLiteGlobal.sDefaultSyncMode = SQLiteGlobal.SYNC_MODE_FULL;
+
             // Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized
             SQLiteCompatibilityWalFlags.init(null);
 
@@ -672,9 +678,17 @@
 
         // Manages Overlay packages
         traceBeginAndSlog("StartOverlayManagerService");
-        mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));
+        OverlayManagerService overlayManagerService = new OverlayManagerService(
+                mSystemContext, installer);
+        mSystemServiceManager.startService(overlayManagerService);
         traceEnd();
 
+        if (SystemProperties.getInt("persist.sys.displayinset.top", 0) > 0) {
+            // DisplayManager needs the overlay immediately.
+            overlayManagerService.updateSystemUiContext();
+            LocalServices.getService(DisplayManagerInternal.class).onOverlayChanged();
+        }
+
         // The sensor service needs access to package manager service, app ops
         // service, and permissions service, therefore we start it after them.
         // Start sensor service in a separate thread. Completion should be checked
diff --git a/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java b/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java
index d0f0fe3..08bcc3d 100644
--- a/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/utils/InsetUtilsTest.java
@@ -16,6 +16,11 @@
 
 package com.android.server.wm.utils;
 
+import static android.hardware.camera2.params.OutputConfiguration.ROTATION_90;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_270;
+
 import static junit.framework.Assert.assertEquals;
 
 import android.graphics.Rect;
@@ -39,5 +44,29 @@
         InsetUtils.addInsets(rect1, rect2);
         assertEquals(new Rect(60, 80, 100, 120), rect1);
     }
+
+    @Test
+    public void rotate() {
+        final Rect original = new Rect(1, 2, 3, 4);
+
+        assertEquals("rot0", original, rotateCopy(original, ROTATION_0));
+
+        final Rect rot90 = rotateCopy(original, ROTATION_90);
+        assertEquals("rot90", new Rect(2, 3, 4, 1), rot90);
+
+        final Rect rot180 = rotateCopy(original, ROTATION_180);
+        assertEquals("rot180", new Rect(3, 4, 1, 2), rot180);
+        assertEquals("rot90(rot90)=rot180", rotateCopy(rot90, ROTATION_90), rot180);
+
+        final Rect rot270 = rotateCopy(original, ROTATION_270);
+        assertEquals("rot270", new Rect(4, 1, 2, 3), rot270);
+        assertEquals("rot90(rot180)=rot270", rotateCopy(rot180, ROTATION_90), rot270);
+    }
+
+    private static Rect rotateCopy(Rect insets, int rotationDelta) {
+        final Rect copy = new Rect(insets);
+        InsetUtils.rotateInsets(copy, rotationDelta);
+        return copy;
+    }
 }
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e0696b3..a8b39e3 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1489,6 +1489,15 @@
             "always_play_remote_hold_tone_bool";
 
     /**
+     * When true, the Telephony stack will automatically turn off airplane mode and retry a wifi
+     * emergency call over the cell network if the initial attempt at dialing was met with a SIP 308
+     * error.
+     * @hide
+     */
+    public static final String KEY_AUTO_RETRY_FAILED_WIFI_EMERGENCY_CALL =
+            "auto_retry_failed_wifi_emergency_call";
+
+    /**
      * When true, indicates that adding a call is disabled when there is an ongoing video call
      * or when there is an ongoing call on wifi which was downgraded from video and VoWifi is
      * turned off.
@@ -2016,6 +2025,7 @@
         sDefaults.putBoolean(KEY_ALLOW_HOLD_IN_IMS_CALL_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_PLAY_REMOTE_HOLD_TONE_BOOL, false);
+        sDefaults.putBoolean(KEY_AUTO_RETRY_FAILED_WIFI_EMERGENCY_CALL, false);
         sDefaults.putBoolean(KEY_ADDITIONAL_CALL_SETTING_BOOL, true);
         sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL, false);
         sDefaults.putStringArray(KEY_UNLOGGABLE_NUMBERS_STRING_ARRAY, null);