Merge "Camera: Release extension resources after closing handler thread" into sc-dev
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index dbaf275..0c64c86 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5654,8 +5654,8 @@
      */
     private void scheduleRelaunchActivityIfPossible(@NonNull ActivityClientRecord r,
             boolean preserveWindow) {
-        if (r.activity.mFinished || r.token instanceof Binder) {
-            // Do not schedule relaunch if the activity is finishing or not a local object (e.g.
+        if ((r.activity != null && r.activity.mFinished) || r.token instanceof Binder) {
+            // Do not schedule relaunch if the activity is finishing or is a local object (e.g.
             // created by ActivtiyGroup that server side doesn't recognize it).
             return;
         }
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4ddb546..d932a29 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -2849,14 +2849,14 @@
     private static final ThreadLocal<Integer> sBinderThreadCallingUid = new ThreadLocal<>();
 
     /**
-     * If a thread is currently executing a two-way binder transaction, this stores the
-     * ops that were noted blaming any app (the caller, the caller of the caller, etc).
+     * If a thread is currently executing a two-way binder transaction, this stores the op-codes of
+     * the app-ops that were noted during this transaction.
      *
      * @see #getNotedOpCollectionMode
      * @see #collectNotedOpSync
      */
-    private static final ThreadLocal<ArrayMap<String, ArrayMap<String, long[]>>>
-            sAppOpsNotedInThisBinderTransaction = new ThreadLocal<>();
+    private static final ThreadLocal<ArrayMap<String, long[]>> sAppOpsNotedInThisBinderTransaction =
+            new ThreadLocal<>();
 
     /** Whether noting for an appop should be collected */
     private static final @ShouldCollectNoteOp byte[] sAppOpsToNote = new byte[_NUM_OP];
@@ -7205,6 +7205,34 @@
      * @hide
      */
     public interface OnOpStartedListener {
+
+        /**
+         * Represents a start operation that was unsuccessful
+         * @hide
+         */
+        public int START_TYPE_FAILED = 0;
+
+        /**
+         * Represents a successful start operation
+         * @hide
+         */
+        public int START_TYPE_STARTED = 1;
+
+        /**
+         * Represents an operation where a restricted operation became unrestricted, and resumed.
+         * @hide
+         */
+        public int START_TYPE_RESUMED = 2;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(flag = true, prefix = { "TYPE_" }, value = {
+            START_TYPE_FAILED,
+            START_TYPE_STARTED,
+            START_TYPE_RESUMED
+        })
+        public @interface StartedType {}
+
         /**
          * Called when an op was started.
          *
@@ -7213,11 +7241,35 @@
          * @param uid The UID performing the operation.
          * @param packageName The package performing the operation.
          * @param attributionTag The attribution tag performing the operation.
-         * @param flags The flags of this op
+         * @param flags The flags of this op.
          * @param result The result of the start.
          */
         void onOpStarted(int op, int uid, String packageName, String attributionTag,
                 @OpFlags int flags, @Mode int result);
+
+        /**
+         * Called when an op was started.
+         *
+         * Note: This is only for op starts. It is not called when an op is noted or stopped.
+         * By default, unless this method is overridden, no code will be executed for resume
+         * events.
+         * @param op The op code.
+         * @param uid The UID performing the operation.
+         * @param packageName The package performing the operation.
+         * @param attributionTag The attribution tag performing the operation.
+         * @param flags The flags of this op.
+         * @param result The result of the start.
+         * @param startType The start type of this start event. Either failed, resumed, or started.
+         * @param attributionFlags The location of this started op in an attribution chain.
+         * @param attributionChainId The ID of the attribution chain of this op, if it is in one.
+         */
+        default void onOpStarted(int op, int uid, String packageName, String attributionTag,
+                @OpFlags int flags, @Mode int result, @StartedType int startType,
+                @AttributionFlags int attributionFlags, int attributionChainId) {
+            if (startType != START_TYPE_RESUMED) {
+                onOpStarted(op, uid, packageName, attributionTag, flags, result);
+            }
+        }
     }
 
     AppOpsManager(Context context, IAppOpsService service) {
@@ -7858,8 +7910,10 @@
              cb = new IAppOpsStartedCallback.Stub() {
                  @Override
                  public void opStarted(int op, int uid, String packageName, String attributionTag,
-                         int flags, int mode) {
-                     callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode);
+                         int flags, int mode, int startType, int attributionFlags,
+                         int attributionChainId) {
+                     callback.onOpStarted(op, uid, packageName, attributionTag, flags, mode,
+                             startType, attributionFlags, attributionChainId);
                  }
              };
              mStartedWatchers.put(callback, cb);
@@ -9052,6 +9106,66 @@
     }
 
     /**
+     * State of a temporarily paused noted app-ops collection.
+     *
+     * @see #pauseNotedAppOpsCollection()
+     *
+     * @hide
+     */
+    public static class PausedNotedAppOpsCollection {
+        final int mUid;
+        final @Nullable ArrayMap<String, long[]> mCollectedNotedAppOps;
+
+        PausedNotedAppOpsCollection(int uid, @Nullable ArrayMap<String,
+                long[]> collectedNotedAppOps) {
+            mUid = uid;
+            mCollectedNotedAppOps = collectedNotedAppOps;
+        }
+    }
+
+    /**
+     * Temporarily suspend collection of noted app-ops when binder-thread calls into the other
+     * process. During such a call there might be call-backs coming back on the same thread which
+     * should not be accounted to the current collection.
+     *
+     * @return a state needed to resume the collection
+     *
+     * @hide
+     */
+    public static @Nullable PausedNotedAppOpsCollection pauseNotedAppOpsCollection() {
+        Integer previousUid = sBinderThreadCallingUid.get();
+        if (previousUid != null) {
+            ArrayMap<String, long[]> previousCollectedNotedAppOps =
+                    sAppOpsNotedInThisBinderTransaction.get();
+
+            sBinderThreadCallingUid.remove();
+            sAppOpsNotedInThisBinderTransaction.remove();
+
+            return new PausedNotedAppOpsCollection(previousUid, previousCollectedNotedAppOps);
+        }
+
+        return null;
+    }
+
+    /**
+     * Resume a collection paused via {@link #pauseNotedAppOpsCollection}.
+     *
+     * @param prevCollection The state of the previous collection
+     *
+     * @hide
+     */
+    public static void resumeNotedAppOpsCollection(
+            @Nullable PausedNotedAppOpsCollection prevCollection) {
+        if (prevCollection != null) {
+            sBinderThreadCallingUid.set(prevCollection.mUid);
+
+            if (prevCollection.mCollectedNotedAppOps != null) {
+                sAppOpsNotedInThisBinderTransaction.set(prevCollection.mCollectedNotedAppOps);
+            }
+        }
+    }
+
+    /**
      * Finish collection of noted appops on this thread.
      *
      * <p>Called at the end of a two way binder transaction.
@@ -9091,47 +9205,26 @@
      */
     @TestApi
     public static void collectNotedOpSync(@NonNull SyncNotedAppOp syncOp) {
-        collectNotedOpSync(sOpStrToOp.get(syncOp.getOp()), syncOp.getAttributionTag(),
-                syncOp.getPackageName());
-    }
-
-    /**
-     * Collect a noted op when inside of a two-way binder call.
-     *
-     * <p> Delivered to caller via {@link #prefixParcelWithAppOpsIfNeeded}
-     *
-     * @param code the op code to note for
-     * @param attributionTag the attribution tag to note for
-     * @param packageName the package to note for
-     */
-    private static void collectNotedOpSync(int code, @Nullable String attributionTag,
-            @NonNull String packageName) {
         // If this is inside of a two-way binder call:
         // We are inside of a two-way binder call. Delivered to caller via
         // {@link #prefixParcelWithAppOpsIfNeeded}
-        ArrayMap<String, ArrayMap<String, long[]>> appOpsNoted =
-                sAppOpsNotedInThisBinderTransaction.get();
+        int op = sOpStrToOp.get(syncOp.getOp());
+        ArrayMap<String, long[]> appOpsNoted = sAppOpsNotedInThisBinderTransaction.get();
         if (appOpsNoted == null) {
             appOpsNoted = new ArrayMap<>(1);
             sAppOpsNotedInThisBinderTransaction.set(appOpsNoted);
         }
 
-        ArrayMap<String, long[]> packageAppOpsNotedForAttribution = appOpsNoted.get(packageName);
-        if (packageAppOpsNotedForAttribution == null) {
-            packageAppOpsNotedForAttribution = new ArrayMap<>(1);
-            appOpsNoted.put(packageName, packageAppOpsNotedForAttribution);
-        }
-
-        long[] appOpsNotedForAttribution = packageAppOpsNotedForAttribution.get(attributionTag);
+        long[] appOpsNotedForAttribution = appOpsNoted.get(syncOp.getAttributionTag());
         if (appOpsNotedForAttribution == null) {
             appOpsNotedForAttribution = new long[2];
-            packageAppOpsNotedForAttribution.put(attributionTag, appOpsNotedForAttribution);
+            appOpsNoted.put(syncOp.getAttributionTag(), appOpsNotedForAttribution);
         }
 
-        if (code < 64) {
-            appOpsNotedForAttribution[0] |= 1L << code;
+        if (op < 64) {
+            appOpsNotedForAttribution[0] |= 1L << op;
         } else {
-            appOpsNotedForAttribution[1] |= 1L << (code - 64);
+            appOpsNotedForAttribution[1] |= 1L << (op - 64);
         }
     }
 
@@ -9185,7 +9278,9 @@
             }
         }
 
-        if (isListeningForOpNotedInBinderTransaction()) {
+        Integer binderUid = sBinderThreadCallingUid.get();
+
+        if (binderUid != null && binderUid == uid) {
             return COLLECT_SYNC;
         } else {
             return COLLECT_ASYNC;
@@ -9204,32 +9299,20 @@
      */
     // TODO (b/186872903) Refactor how sync noted ops are propagated.
     public static void prefixParcelWithAppOpsIfNeeded(@NonNull Parcel p) {
-        if (!isListeningForOpNotedInBinderTransaction()) {
-            return;
-        }
-        final ArrayMap<String, ArrayMap<String, long[]>> notedAppOps =
-                sAppOpsNotedInThisBinderTransaction.get();
+        ArrayMap<String, long[]> notedAppOps = sAppOpsNotedInThisBinderTransaction.get();
         if (notedAppOps == null) {
             return;
         }
 
         p.writeInt(Parcel.EX_HAS_NOTED_APPOPS_REPLY_HEADER);
 
-        final int packageCount = notedAppOps.size();
-        p.writeInt(packageCount);
+        int numAttributionWithNotesAppOps = notedAppOps.size();
+        p.writeInt(numAttributionWithNotesAppOps);
 
-        for (int i = 0; i < packageCount; i++) {
+        for (int i = 0; i < numAttributionWithNotesAppOps; i++) {
             p.writeString(notedAppOps.keyAt(i));
-
-            final ArrayMap<String, long[]> notedTagAppOps = notedAppOps.valueAt(i);
-            final int tagCount = notedTagAppOps.size();
-            p.writeInt(tagCount);
-
-            for (int j = 0; j < tagCount; j++) {
-                p.writeString(notedTagAppOps.keyAt(j));
-                p.writeLong(notedTagAppOps.valueAt(j)[0]);
-                p.writeLong(notedTagAppOps.valueAt(j)[1]);
-            }
+            p.writeLong(notedAppOps.valueAt(i)[0]);
+            p.writeLong(notedAppOps.valueAt(i)[1]);
         }
     }
 
@@ -9244,54 +9327,36 @@
      * @hide
      */
     public static void readAndLogNotedAppops(@NonNull Parcel p) {
-        final int packageCount = p.readInt();
-        if (packageCount <= 0) {
-            return;
-        }
+        int numAttributionsWithNotedAppOps = p.readInt();
 
-        final String myPackageName = ActivityThread.currentPackageName();
+        for (int i = 0; i < numAttributionsWithNotedAppOps; i++) {
+            String attributionTag = p.readString();
+            long[] rawNotedAppOps = new long[2];
+            rawNotedAppOps[0] = p.readLong();
+            rawNotedAppOps[1] = p.readLong();
 
-        synchronized (sLock) {
-            for (int i = 0; i < packageCount; i++) {
-                final String packageName = p.readString();
+            if (rawNotedAppOps[0] != 0 || rawNotedAppOps[1] != 0) {
+                BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps);
 
-                final int tagCount = p.readInt();
-                for (int j = 0; j < tagCount; j++) {
-                    final String attributionTag = p.readString();
-                    final long[] rawNotedAppOps = new long[2];
-                    rawNotedAppOps[0] = p.readLong();
-                    rawNotedAppOps[1] = p.readLong();
-
-                    if (rawNotedAppOps[0] == 0 && rawNotedAppOps[1] == 0) {
-                        continue;
-                    }
-
-                    final BitSet notedAppOps = BitSet.valueOf(rawNotedAppOps);
+                synchronized (sLock) {
                     for (int code = notedAppOps.nextSetBit(0); code != -1;
                             code = notedAppOps.nextSetBit(code + 1)) {
-                        if (Objects.equals(myPackageName, packageName)) {
-                            if (sOnOpNotedCallback != null) {
-                                sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code,
-                                        attributionTag, packageName));
-                            } else {
-                                String message = getFormattedStackTrace();
-                                sUnforwardedOps.add(new AsyncNotedAppOp(code, Process.myUid(),
-                                        attributionTag, message, System.currentTimeMillis()));
-                                if (sUnforwardedOps.size() > MAX_UNFORWARDED_OPS) {
-                                    sUnforwardedOps.remove(0);
-                                }
+                        if (sOnOpNotedCallback != null) {
+                            sOnOpNotedCallback.onNoted(new SyncNotedAppOp(code, attributionTag));
+                        } else {
+                            String message = getFormattedStackTrace();
+                            sUnforwardedOps.add(
+                                    new AsyncNotedAppOp(code, Process.myUid(), attributionTag,
+                                            message, System.currentTimeMillis()));
+                            if (sUnforwardedOps.size() > MAX_UNFORWARDED_OPS) {
+                                sUnforwardedOps.remove(0);
                             }
-                        } else if (isListeningForOpNotedInBinderTransaction()) {
-                            collectNotedOpSync(code, attributionTag, packageName);
                         }
                     }
-                    for (int code = notedAppOps.nextSetBit(0); code != -1;
-                            code = notedAppOps.nextSetBit(code + 1)) {
-                        if (Objects.equals(myPackageName, packageName)) {
-                            sMessageCollector.onNoted(new SyncNotedAppOp(code,
-                                    attributionTag, packageName));
-                        }
-                    }
+                }
+                for (int code = notedAppOps.nextSetBit(0); code != -1;
+                        code = notedAppOps.nextSetBit(code + 1)) {
+                    sMessageCollector.onNoted(new SyncNotedAppOp(code, attributionTag));
                 }
             }
         }
@@ -9398,15 +9463,7 @@
      * @hide
      */
     public static boolean isListeningForOpNoted() {
-        return sOnOpNotedCallback != null || isListeningForOpNotedInBinderTransaction()
-                || isCollectingStackTraces();
-    }
-
-    /**
-     * @return whether we are in a binder transaction and collecting appops.
-     */
-    private static boolean isListeningForOpNotedInBinderTransaction() {
-        return sBinderThreadCallingUid.get() != null;
+        return sOnOpNotedCallback != null || isCollectingStackTraces();
     }
 
     /**
diff --git a/core/java/android/app/SyncNotedAppOp.java b/core/java/android/app/SyncNotedAppOp.java
index 32d889e..7c0c08a 100644
--- a/core/java/android/app/SyncNotedAppOp.java
+++ b/core/java/android/app/SyncNotedAppOp.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.os.Parcelable;
-import android.os.Process;
 
 import com.android.internal.annotations.Immutable;
 import com.android.internal.util.DataClass;
@@ -29,6 +28,8 @@
 /**
  * Description of an app-op that was noted for the current process.
  *
+ * Note: package name is currently unused in the system.
+ *
  * <p>This is either delivered after a
  * {@link AppOpsManager.OnOpNotedCallback#onNoted(SyncNotedAppOp) two way binder call} or
  * when the app
diff --git a/core/java/android/appwidget/AppWidgetManagerInternal.java b/core/java/android/appwidget/AppWidgetManagerInternal.java
index 266e33a..5694ca8 100644
--- a/core/java/android/appwidget/AppWidgetManagerInternal.java
+++ b/core/java/android/appwidget/AppWidgetManagerInternal.java
@@ -19,8 +19,6 @@
 import android.annotation.Nullable;
 import android.util.ArraySet;
 
-import java.util.Set;
-
 /**
  * App widget manager local system service interface.
  *
@@ -44,16 +42,4 @@
      * @param userId The user that is being unlocked.
      */
     public abstract void unlockUser(int userId);
-
-    /**
-     * Updates all widgets, applying changes to Runtime Resource Overlay affecting the specified
-     * target packages.
-     *
-     * @param packageNames The names of all target packages for which an overlay was modified
-     * @param userId The user for which overlay modifications occurred.
-     * @param updateFrameworkRes Whether or not an overlay affected the values of framework
-     *                           resources.
-     */
-    public abstract void applyResourceOverlaysToWidgets(Set<String> packageNames, int userId,
-            boolean updateFrameworkRes);
 }
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index a741f96..c714f507 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -745,9 +745,6 @@
         if (Binder.getCallingPid() == Process.myPid()) {
             return PermissionChecker.PERMISSION_GRANTED;
         }
-        if (!attributionSource.checkCallingUid()) {
-            return PermissionChecker.PERMISSION_HARD_DENIED;
-        }
         return PermissionChecker.checkPermissionForDataDeliveryFromDataSource(getContext(),
                 permission, -1, new AttributionSource(getContext().getAttributionSource(),
                         attributionSource), /*message*/ null);
diff --git a/core/java/android/hardware/camera2/MultiResolutionImageReader.java b/core/java/android/hardware/camera2/MultiResolutionImageReader.java
index 3af1b5b..0dbf29d 100644
--- a/core/java/android/hardware/camera2/MultiResolutionImageReader.java
+++ b/core/java/android/hardware/camera2/MultiResolutionImageReader.java
@@ -91,7 +91,7 @@
      * </p>
      * <p>
      * The {@code maxImages} parameter determines the maximum number of
-     * {@link Image} objects that can be be acquired from each of the {@code ImageReader}
+     * {@link Image} objects that can be acquired from each of the {@code ImageReader}
      * within the {@code MultiResolutionImageReader}. However, requesting more buffers will
      * use up more memory, so it is important to use only the minimum number necessary. The
      * application is strongly recommended to acquire no more than {@code maxImages} images
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 8fd9a6a..196134b 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1720,21 +1720,21 @@
                 new SetCommand() {
             @Override
             public <T> void setValue(CameraMetadataNative metadata, T value) {
-                metadata.setAWBRegions((MeteringRectangle[]) value);
+                metadata.setAWBRegions(value);
             }
         });
         sSetCommandMap.put(CaptureRequest.CONTROL_AF_REGIONS.getNativeKey(),
                 new SetCommand() {
             @Override
             public <T> void setValue(CameraMetadataNative metadata, T value) {
-                metadata.setAFRegions((MeteringRectangle[]) value);
+                metadata.setAFRegions(value);
             }
         });
         sSetCommandMap.put(CaptureRequest.CONTROL_AE_REGIONS.getNativeKey(),
                 new SetCommand() {
             @Override
             public <T> void setValue(CameraMetadataNative metadata, T value) {
-                metadata.setAERegions((MeteringRectangle[]) value);
+                metadata.setAERegions(value);
             }
         });
     }
@@ -1815,30 +1815,33 @@
         return true;
     }
 
-    private <T> boolean setAFRegions(MeteringRectangle[] afRegions) {
+    private <T> boolean setAFRegions(T afRegions) {
         if (afRegions == null) {
             return false;
         }
         setBase(CaptureRequest.CONTROL_AF_REGIONS_SET, true);
-        setBase(CaptureRequest.CONTROL_AF_REGIONS, afRegions);
+        // The cast to CaptureRequest.Key is needed since java does not support template
+        // specialization and we need to route this method to
+        // setBase(CaptureRequest.Key<T> key, T value)
+        setBase((CaptureRequest.Key)CaptureRequest.CONTROL_AF_REGIONS, afRegions);
         return true;
     }
 
-    private <T> boolean setAERegions(MeteringRectangle[] aeRegions) {
+    private <T> boolean setAERegions(T aeRegions) {
         if (aeRegions == null) {
             return false;
         }
         setBase(CaptureRequest.CONTROL_AE_REGIONS_SET, true);
-        setBase(CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
+        setBase((CaptureRequest.Key)CaptureRequest.CONTROL_AE_REGIONS, aeRegions);
         return true;
     }
 
-    private <T> boolean setAWBRegions(MeteringRectangle[] awbRegions) {
+    private <T> boolean setAWBRegions(T awbRegions) {
         if (awbRegions == null) {
             return false;
         }
         setBase(CaptureRequest.CONTROL_AWB_REGIONS_SET, true);
-        setBase(CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
+        setBase((CaptureRequest.Key)CaptureRequest.CONTROL_AWB_REGIONS, awbRegions);
         return true;
     }
 
diff --git a/core/java/android/hardware/camera2/params/InputConfiguration.java b/core/java/android/hardware/camera2/params/InputConfiguration.java
index 8dfc0a7b..70c85a1 100644
--- a/core/java/android/hardware/camera2/params/InputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/InputConfiguration.java
@@ -42,7 +42,7 @@
     private final boolean mIsMultiResolution;
 
     /**
-     * Create an input configration with the width, height, and user-defined format.
+     * Create an input configuration with the width, height, and user-defined format.
      *
      * <p>Images of a user-defined format are accessible by applications. Use
      * {@link android.hardware.camera2.CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP}
@@ -64,7 +64,7 @@
     }
 
     /**
-     * Create an input configration with the format and a list of multi-resolution input stream
+     * Create an input configuration with the format and a list of multi-resolution input stream
      * info.
      *
      * <p>Use {@link
@@ -108,7 +108,7 @@
     }
 
     /**
-     * Get the width of this input configration.
+     * Get the width of this input configuration.
      *
      * @return width of this input configuration.
      */
@@ -117,7 +117,7 @@
     }
 
     /**
-     * Get the height of this input configration.
+     * Get the height of this input configuration.
      *
      * @return height of this input configuration.
      */
@@ -126,7 +126,7 @@
     }
 
     /**
-     * Get the format of this input configration.
+     * Get the format of this input configuration.
      *
      * @return format of this input configuration.
      */
diff --git a/core/java/android/os/BinderProxy.java b/core/java/android/os/BinderProxy.java
index d44b016..3d466a0 100644
--- a/core/java/android/os/BinderProxy.java
+++ b/core/java/android/os/BinderProxy.java
@@ -560,6 +560,9 @@
             }
         }
 
+        final AppOpsManager.PausedNotedAppOpsCollection prevCollection =
+                AppOpsManager.pauseNotedAppOpsCollection();
+
         if ((flags & FLAG_ONEWAY) == 0 && AppOpsManager.isListeningForOpNoted()) {
             flags |= FLAG_COLLECT_NOTED_APP_OPS;
         }
@@ -567,6 +570,8 @@
         try {
             return transactNative(code, data, reply, flags);
         } finally {
+            AppOpsManager.resumeNotedAppOpsCollection(prevCollection);
+
             if (transactListener != null) {
                 transactListener.onTransactEnded(session);
             }
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 03f94c5..19f204b 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -31,7 +31,9 @@
 import static android.app.AppOpsManager.OPSTR_PHONE_CALL_CAMERA;
 import static android.app.AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE;
 import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.AppOpsManager.OP_FLAGS_ALL_TRUSTED;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.media.AudioSystem.MODE_IN_COMMUNICATION;
 import static android.telephony.TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
 
@@ -63,7 +65,8 @@
  *
  * @hide
  */
-public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener {
+public class PermissionUsageHelper implements AppOpsManager.OnOpActiveChangedListener,
+        AppOpsManager.OnOpStartedListener {
 
     /** Whether to show the mic and camera icons.  */
     private static final String PROPERTY_CAMERA_MIC_ICONS_ENABLED = "camera_mic_icons_enabled";
@@ -160,9 +163,10 @@
         mUserContexts = new ArrayMap<>();
         mUserContexts.put(Process.myUserHandle(), mContext);
         // TODO ntmyren: make this listen for flag enable/disable changes
-        String[] ops = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO };
-        mContext.getSystemService(AppOpsManager.class).startWatchingActive(ops,
-                context.getMainExecutor(), this);
+        String[] opStrs = { OPSTR_CAMERA, OPSTR_RECORD_AUDIO };
+        mAppOpsManager.startWatchingActive(opStrs, context.getMainExecutor(), this);
+        int[] ops = { OP_CAMERA, OP_RECORD_AUDIO };
+        mAppOpsManager.startWatchingStarted(ops, this);
     }
 
     private Context getUserContext(UserHandle user) {
@@ -182,25 +186,65 @@
     public void onOpActiveChanged(@NonNull String op, int uid, @NonNull String packageName,
             @Nullable String attributionTag, boolean active, @AttributionFlags int attributionFlags,
             int attributionChainId) {
-        if (attributionChainId == ATTRIBUTION_CHAIN_ID_NONE
-                || attributionFlags == ATTRIBUTION_FLAGS_NONE
-                || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) {
-            // If this is not a chain, or it is untrusted, return
+        if (active) {
+            // Started callback handles these
             return;
         }
 
-        if (!active) {
-            // if any link in the chain is finished, remove the chain.
-            // TODO ntmyren: be smarter about this
-            mAttributionChains.remove(attributionChainId);
+        // if any link in the chain is finished, remove the chain. Then, find any other chains that
+        // contain this op/package/uid/tag combination, and remove them, as well.
+        // TODO ntmyren: be smarter about this
+        mAttributionChains.remove(attributionChainId);
+        int numChains = mAttributionChains.size();
+        ArrayList<Integer> toRemove = new ArrayList<>();
+        for (int i = 0; i < numChains; i++) {
+            int chainId = mAttributionChains.keyAt(i);
+            ArrayList<AccessChainLink> chain = mAttributionChains.valueAt(i);
+            int chainSize = chain.size();
+            for (int j = 0; j < chainSize; j++) {
+                AccessChainLink link = chain.get(j);
+                if (link.packageAndOpEquals(op, packageName, attributionTag, uid)) {
+                    toRemove.add(chainId);
+                    break;
+                }
+            }
+        }
+        mAttributionChains.removeAll(toRemove);
+    }
+
+    @Override
+    public void onOpStarted(int op, int uid, String packageName, String attributionTag,
+                @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result) {
+       // not part of an attribution chain. Do nothing
+    }
+
+    @Override
+    public void onOpStarted(int op, int uid, String packageName, String attributionTag,
+            @AppOpsManager.OpFlags int flags, @AppOpsManager.Mode int result,
+            @StartedType int startedType, @AttributionFlags int attributionFlags,
+            int attributionChainId) {
+        if (startedType == START_TYPE_FAILED || attributionChainId == ATTRIBUTION_CHAIN_ID_NONE
+                || attributionFlags == ATTRIBUTION_FLAGS_NONE
+                || (attributionFlags & ATTRIBUTION_FLAG_TRUSTED) == 0) {
+            // If this is not a successful start, or it is not a chain, or it is untrusted, return
             return;
         }
+        addLinkToChainIfNotPresent(AppOpsManager.opToPublicName(op), packageName, uid,
+                attributionTag, attributionFlags, attributionChainId);
+    }
+
+    private void addLinkToChainIfNotPresent(String op, String packageName, int uid,
+            String attributionTag, int attributionFlags, int attributionChainId) {
 
         ArrayList<AccessChainLink> currentChain = mAttributionChains.computeIfAbsent(
                 attributionChainId, k -> new ArrayList<>());
         AccessChainLink link = new AccessChainLink(op, packageName, attributionTag, uid,
                 attributionFlags);
 
+        if (currentChain.contains(link)) {
+            return;
+        }
+
         int currSize = currentChain.size();
         if (currSize == 0 || link.isEnd() || !currentChain.get(currSize - 1).isEnd()) {
             // if the list is empty, this link is the end, or the last link in the current chain
@@ -613,5 +657,21 @@
         public boolean isStart() {
             return (flags & ATTRIBUTION_FLAG_RECEIVER) != 0;
         }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof AccessChainLink)) {
+                return false;
+            }
+            AccessChainLink other = (AccessChainLink) obj;
+            return other.flags == flags && packageAndOpEquals(other.usage.op,
+                    other.usage.packageName, other.usage.attributionTag, other.usage.uid);
+        }
+
+        public boolean packageAndOpEquals(String op, String packageName, String attributionTag,
+                int uid) {
+            return Objects.equals(op, usage.op) && Objects.equals(packageName, usage.packageName)
+                    && Objects.equals(attributionTag, usage.attributionTag) && uid == usage.uid;
+        }
     }
 }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index f21d855dd..c1956e4 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -33,6 +33,7 @@
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.RenderNode;
@@ -237,15 +238,6 @@
             new SurfaceControl.Transaction();
 
     /**
-     * Transaction that should be used for
-     * {@link RenderNode.PositionUpdateListener#positionChanged(long, int, int, int, int)}
-     * The callback is invoked from a thread pool so it's not thread safe with other render thread
-     * transactions. Keep the transactions for position changed callbacks on its own transaction.
-     */
-    private final SurfaceControl.Transaction mPositionChangedTransaction =
-            new SurfaceControl.Transaction();
-
-    /**
      * A temporary transaction holder that should only be used when applying right away. There
      * should be no assumption about thread safety for this transaction.
      */
@@ -295,7 +287,6 @@
             int defStyleRes, boolean disableBackgroundLayer) {
         super(context, attrs, defStyleAttr, defStyleRes);
         mUseBlastAdapter = useBlastAdapter(context);
-        mRenderNode.addPositionUpdateListener(mPositionListener);
 
         setWillNotDraw(true);
         mDisableBackgroundLayer = disableBackgroundLayer;
@@ -943,6 +934,24 @@
         }
     }
 
+
+    // The position update listener is used to safely share the surface size between render thread
+    // workers and the UI thread. Both threads need to know the surface size to determine the scale.
+    // The parent layer scales the surface size to view size. The child (BBQ) layer scales
+    // the buffer to the surface size. Both scales along with the window crop must be applied
+    // synchronously otherwise we may see flickers.
+    // When the listener is updated, we will get at least a single position update call so we can
+    // guarantee any changes we post will be applied.
+    private void replacePositionUpdateListener(int surfaceWidth, int surfaceHeight,
+            @Nullable Transaction geometryTransaction) {
+        if (mPositionListener != null) {
+            mRenderNode.removePositionUpdateListener(mPositionListener);
+        }
+        mPositionListener = new SurfaceViewPositionUpdateListener(surfaceWidth, surfaceHeight,
+                geometryTransaction);
+        mRenderNode.addPositionUpdateListener(mPositionListener);
+    }
+
     private boolean performSurfaceTransaction(ViewRootImpl viewRoot, Translator translator,
             boolean creating, boolean sizeChanged, boolean hintChanged) {
         boolean realSizeChanged = false;
@@ -985,13 +994,13 @@
             // While creating the surface, we will set it's initial
             // geometry. Outside of that though, we should generally
             // leave it to the RenderThread.
-            //
-            // There is one more case when the buffer size changes we aren't yet
-            // prepared to sync (as even following the transaction applying
-            // we still need to latch a buffer).
-            // b/28866173
-            if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
-                onSetSurfacePositionAndScaleRT(mTmpTransaction, mSurfaceControl,
+            Transaction geometryTransaction = new Transaction();
+            geometryTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
+            if ((sizeChanged || hintChanged) && !creating) {
+                setBufferSize(geometryTransaction);
+            }
+            if (sizeChanged || creating || !isHardwareAccelerated()) {
+                onSetSurfacePositionAndScaleRT(geometryTransaction, mSurfaceControl,
                         mScreenRect.left, /*positionLeft*/
                         mScreenRect.top /*positionTop*/ ,
                         mScreenRect.width() / (float) mSurfaceWidth /*postScaleX*/,
@@ -1002,17 +1011,31 @@
                 // use SCALING_MODE_SCALE and submit a larger size than the surface
                 // size.
                 if (mClipSurfaceToBounds && mClipBounds != null) {
-                    mTmpTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
+                    geometryTransaction.setWindowCrop(mSurfaceControl, mClipBounds);
                 } else {
-                    mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
+                    geometryTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
                             mSurfaceHeight);
                 }
-            }
-            mTmpTransaction.setCornerRadius(mSurfaceControl, mCornerRadius);
-            if ((sizeChanged || hintChanged) && !creating) {
-                setBufferSize(mTmpTransaction);
-            }
 
+                boolean applyChangesOnRenderThread =
+                        sizeChanged && !creating && isHardwareAccelerated();
+                if (isHardwareAccelerated()) {
+                    // This will consume the passed in transaction and the transaction will be
+                    // applied on a render worker thread.
+                    replacePositionUpdateListener(mSurfaceWidth, mSurfaceHeight,
+                            applyChangesOnRenderThread ? geometryTransaction : null);
+                }
+                if (DEBUG_POSITION) {
+                    Log.d(TAG, String.format(
+                            "%d updateSurfacePosition %s"
+                                + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
+                            System.identityHashCode(this),
+                            applyChangesOnRenderThread ? "RenderWorker" : "UiThread",
+                            mScreenRect.left, mScreenRect.top, mScreenRect.right,
+                            mScreenRect.bottom, mSurfaceWidth, mSurfaceHeight));
+                }
+            }
+            mTmpTransaction.merge(geometryTransaction);
             mTmpTransaction.apply();
             updateEmbeddedAccessibilityMatrix();
 
@@ -1242,7 +1265,7 @@
             mBlastSurfaceControl.setTransformHint(mTransformHint);
             if (mBlastBufferQueue != null) {
                 mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight,
-                        mFormat);
+                        mFormat, transaction);
             }
         } else {
             transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight);
@@ -1399,19 +1422,6 @@
         mTmpTransaction.apply();
     }
 
-    private void applySurfaceTransforms(SurfaceControl surface, SurfaceControl.Transaction t,
-            Rect position) {
-        onSetSurfacePositionAndScaleRT(t, surface,
-                position.left /*positionLeft*/,
-                position.top /*positionTop*/,
-                position.width() / (float) mSurfaceWidth /*postScaleX*/,
-                position.height() / (float) mSurfaceHeight /*postScaleY*/);
-
-        if (mViewVisibility) {
-            t.show(surface);
-        }
-    }
-
     /**
      * @return The last render position of the backing surface or an empty rect.
      *
@@ -1421,13 +1431,6 @@
         return mRTLastReportedPosition;
     }
 
-    private void setParentSpaceRectangle(Rect position, long frameNumber, Transaction t) {
-        final ViewRootImpl viewRoot = getViewRootImpl();
-        applySurfaceTransforms(mSurfaceControl, t, position);
-        applyChildSurfaceTransaction_renderWorker(t, viewRoot.mSurface, frameNumber);
-        applyOrMergeTransaction(t, frameNumber);
-    }
-
     private void applyOrMergeTransaction(Transaction t, long frameNumber) {
         final ViewRootImpl viewRoot = getViewRootImpl();
         boolean useBLAST = viewRoot != null && useBLASTSync(viewRoot);
@@ -1440,9 +1443,24 @@
     }
 
     private Rect mRTLastReportedPosition = new Rect();
+    private Point mRTLastReportedSurfaceSize = new Point();
 
-    private RenderNode.PositionUpdateListener mPositionListener =
-            new RenderNode.PositionUpdateListener() {
+    private class SurfaceViewPositionUpdateListener implements RenderNode.PositionUpdateListener {
+        int mRtSurfaceWidth = -1;
+        int mRtSurfaceHeight = -1;
+        private final SurfaceControl.Transaction mPositionChangedTransaction =
+                new SurfaceControl.Transaction();
+        boolean mPendingTransaction = false;
+
+        SurfaceViewPositionUpdateListener(int surfaceWidth, int surfaceHeight,
+                @Nullable Transaction t) {
+            mRtSurfaceWidth = surfaceWidth;
+            mRtSurfaceHeight = surfaceHeight;
+            if (t != null) {
+                mPositionChangedTransaction.merge(t);
+                mPendingTransaction = true;
+            }
+        }
 
         @Override
         public void positionChanged(long frameNumber, int left, int top, int right, int bottom) {
@@ -1464,21 +1482,34 @@
             if (mRTLastReportedPosition.left == left
                     && mRTLastReportedPosition.top == top
                     && mRTLastReportedPosition.right == right
-                    && mRTLastReportedPosition.bottom == bottom) {
+                    && mRTLastReportedPosition.bottom == bottom
+                    && mRTLastReportedSurfaceSize.x == mRtSurfaceWidth
+                    && mRTLastReportedSurfaceSize.y == mRtSurfaceHeight
+                    && !mPendingTransaction) {
                 return;
             }
             try {
                 if (DEBUG_POSITION) {
                     Log.d(TAG, String.format(
                             "%d updateSurfacePosition RenderWorker, frameNr = %d, "
-                                    + "position = [%d, %d, %d, %d]",
-                            System.identityHashCode(this), frameNumber,
-                            left, top, right, bottom));
+                                    + "position = [%d, %d, %d, %d] surfaceSize = %dx%d",
+                            System.identityHashCode(SurfaceView.this), frameNumber,
+                            left, top, right, bottom, mRtSurfaceWidth, mRtSurfaceHeight));
                 }
                 mRTLastReportedPosition.set(left, top, right, bottom);
-                setParentSpaceRectangle(mRTLastReportedPosition, frameNumber,
-                        mPositionChangedTransaction);
-                // Now overwrite mRTLastReportedPosition with our values
+                mRTLastReportedSurfaceSize.set(mRtSurfaceWidth, mRtSurfaceHeight);
+                onSetSurfacePositionAndScaleRT(mPositionChangedTransaction, mSurfaceControl,
+                        mRTLastReportedPosition.left /*positionLeft*/,
+                        mRTLastReportedPosition.top /*positionTop*/,
+                        mRTLastReportedPosition.width() / (float) mRtSurfaceWidth /*postScaleX*/,
+                        mRTLastReportedPosition.height() / (float) mRtSurfaceHeight /*postScaleY*/);
+                if (mViewVisibility) {
+                    mPositionChangedTransaction.show(mSurfaceControl);
+                }
+                applyChildSurfaceTransaction_renderWorker(mPositionChangedTransaction,
+                        getViewRootImpl().mSurface, frameNumber);
+                applyOrMergeTransaction(mPositionChangedTransaction, frameNumber);
+                mPendingTransaction = false;
             } catch (Exception ex) {
                 Log.e(TAG, "Exception from repositionChild", ex);
             }
@@ -1502,7 +1533,13 @@
                         System.identityHashCode(this), frameNumber));
             }
             mRTLastReportedPosition.setEmpty();
-
+            mRTLastReportedSurfaceSize.set(-1, -1);
+            if (mPendingTransaction) {
+                Log.w(TAG, System.identityHashCode(SurfaceView.this)
+                        + "Pending transaction cleared.");
+                mPositionChangedTransaction.clear();
+                mPendingTransaction = false;
+            }
             if (mSurfaceControl == null) {
                 return;
             }
@@ -1521,7 +1558,9 @@
                 mRtHandlingPositionUpdates = false;
             }
         }
-    };
+    }
+
+    private SurfaceViewPositionUpdateListener mPositionListener = null;
 
     private SurfaceHolder.Callback[] getSurfaceCallbacks() {
         SurfaceHolder.Callback[] callbacks;
diff --git a/core/java/android/view/translation/Translator.java b/core/java/android/view/translation/Translator.java
index edd0d16..606f39d 100644
--- a/core/java/android/view/translation/Translator.java
+++ b/core/java/android/view/translation/Translator.java
@@ -18,6 +18,7 @@
 
 import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_FAIL;
 import static android.view.translation.TranslationManager.SYNC_CALLS_TIMEOUT_MS;
+import static android.view.translation.UiTranslationController.DEBUG;
 
 import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
@@ -38,7 +39,6 @@
 import com.android.internal.os.IResultReceiver;
 
 import java.io.PrintWriter;
-import java.lang.ref.WeakReference;
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
@@ -395,27 +395,26 @@
 
     private static class TranslationResponseCallbackImpl extends ITranslationCallback.Stub {
 
-        private final WeakReference<Consumer<TranslationResponse>> mCallback;
-        private final WeakReference<Executor> mExecutor;
+        private final Consumer<TranslationResponse> mCallback;
+        private final Executor mExecutor;
 
         TranslationResponseCallbackImpl(Consumer<TranslationResponse> callback, Executor executor) {
-            mCallback = new WeakReference<>(callback);
-            mExecutor = new WeakReference<>(executor);
+            mCallback = callback;
+            mExecutor = executor;
         }
 
         @Override
         public void onTranslationResponse(TranslationResponse response) throws RemoteException {
-            final Consumer<TranslationResponse> callback = mCallback.get();
+            if (DEBUG) {
+                Log.i(TAG, "onTranslationResponse called.");
+            }
             final Runnable runnable =
-                    () -> callback.accept(response);
-            if (callback != null) {
-                final Executor executor = mExecutor.get();
-                final long token = Binder.clearCallingIdentity();
-                try {
-                    executor.execute(runnable);
-                } finally {
-                    restoreCallingIdentity(token);
-                }
+                    () -> mCallback.accept(response);
+            final long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(runnable);
+            } finally {
+                restoreCallingIdentity(token);
             }
         }
     }
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 91fc5a5..e827f0a 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -5824,25 +5824,6 @@
         return false;
     }
 
-    /** @hide */
-    public void updateAppInfo(@NonNull ApplicationInfo info) {
-        if (mApplication != null && mApplication.sourceDir.equals(info.sourceDir)) {
-            // Overlay paths are generated against a particular version of an application.
-            // The overlays paths of a newly upgraded application are incompatible with the
-            // old version of the application.
-            mApplication = info;
-        }
-        if (hasSizedRemoteViews()) {
-            for (RemoteViews layout : mSizedRemoteViews) {
-                layout.updateAppInfo(info);
-            }
-        }
-        if (hasLandscapeAndPortraitLayouts()) {
-            mLandscape.updateAppInfo(info);
-            mPortrait.updateAppInfo(info);
-        }
-    }
-
     private Context getContextForResources(Context context) {
         if (mApplication != null) {
             if (context.getUserId() == UserHandle.getUserId(mApplication.uid)
diff --git a/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
index 3a108e7..06640cb 100644
--- a/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
+++ b/core/java/com/android/internal/app/IAppOpsStartedCallback.aidl
@@ -18,5 +18,6 @@
 
 // Iterface to observe op starts
 oneway interface IAppOpsStartedCallback {
-    void opStarted(int op, int uid, String packageName, String attributionTag, int flags, int mode);
+    void opStarted(int op, int uid, String packageName, String attributionTag, int flags, int mode,
+    int startedType, int attributionFlags, int attributionChainId);
 }
diff --git a/core/jni/android_graphics_BLASTBufferQueue.cpp b/core/jni/android_graphics_BLASTBufferQueue.cpp
index b46b5a2..d4ae6d7 100644
--- a/core/jni/android_graphics_BLASTBufferQueue.cpp
+++ b/core/jni/android_graphics_BLASTBufferQueue.cpp
@@ -105,9 +105,11 @@
 }
 
 static void nativeUpdate(JNIEnv* env, jclass clazz, jlong ptr, jlong surfaceControl, jlong width,
-                         jlong height, jint format) {
+                         jlong height, jint format, jlong transactionPtr) {
     sp<BLASTBufferQueue> queue = reinterpret_cast<BLASTBufferQueue*>(ptr);
-    queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format);
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionPtr);
+    queue->update(reinterpret_cast<SurfaceControl*>(surfaceControl), width, height, format,
+                  transaction);
 }
 
 static void nativeFlushShadowQueue(JNIEnv* env, jclass clazz, jlong ptr) {
@@ -144,7 +146,7 @@
         {"nativeGetSurface", "(JZ)Landroid/view/Surface;", (void*)nativeGetSurface},
         {"nativeDestroy", "(J)V", (void*)nativeDestroy},
         {"nativeSetNextTransaction", "(JJ)V", (void*)nativeSetNextTransaction},
-        {"nativeUpdate", "(JJJJI)V", (void*)nativeUpdate},
+        {"nativeUpdate", "(JJJJIJ)V", (void*)nativeUpdate},
         {"nativeFlushShadowQueue", "(J)V", (void*)nativeFlushShadowQueue},
         {"nativeMergeWithNextTransaction", "(JJJ)V", (void*)nativeMergeWithNextTransaction},
         {"nativeSetTransactionCompleteCallback",
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 16ee6a7..4b93363 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -2429,6 +2429,12 @@
     return (jint)nativeToJavaStatus(status);
 }
 
+static jint android_media_AudioSystem_setHotwordDetectionServiceUid(JNIEnv *env, jobject thiz,
+                                                                    jint uid) {
+    status_t status = AudioSystem::setHotwordDetectionServiceUid(uid);
+    return (jint)nativeToJavaStatus(status);
+}
+
 static jint
 android_media_AudioSystem_setA11yServicesUids(JNIEnv *env, jobject thiz, jintArray uids) {
     std::vector<uid_t> nativeUidsVector;
@@ -2799,6 +2805,8 @@
          {"setSurroundFormatEnabled", "(IZ)I",
           (void *)android_media_AudioSystem_setSurroundFormatEnabled},
          {"setAssistantUid", "(I)I", (void *)android_media_AudioSystem_setAssistantUid},
+         {"setHotwordDetectionServiceUid", "(I)I",
+          (void *)android_media_AudioSystem_setHotwordDetectionServiceUid},
          {"setA11yServicesUids", "([I)I", (void *)android_media_AudioSystem_setA11yServicesUids},
          {"isHapticPlaybackSupported", "()Z",
           (void *)android_media_AudioSystem_isHapticPlaybackSupported},
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 95c24ad..bad79eb 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -550,6 +550,8 @@
     <protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" />
     <protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />
     <protected-broadcast android:name="com.android.settings.bluetooth.ACTION_DISMISS_PAIRING" />
+    <protected-broadcast android:name="com.android.settings.network.DELETE_SUBSCRIPTION" />
+    <protected-broadcast android:name="com.android.settings.network.SWITCH_TO_SUBSCRIPTION" />
     <protected-broadcast android:name="com.android.settings.wifi.action.NETWORK_REQUEST" />
 
     <protected-broadcast android:name="NotificationManagerService.TIMEOUT" />
diff --git a/core/res/res/layout/splash_screen_view.xml b/core/res/res/layout/splash_screen_view.xml
index aa050f3..2b9f952 100644
--- a/core/res/res/layout/splash_screen_view.xml
+++ b/core/res/res/layout/splash_screen_view.xml
@@ -26,6 +26,7 @@
           android:layout_width="wrap_content"
           android:layout_gravity="center"
           android:padding="0dp"
+          android:background="@null"
           android:contentDescription="@string/splash_screen_view_icon_description"/>
 
     <View android:id="@+id/splashscreen_branding_view"
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 199e82f..865f026 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1937,7 +1937,7 @@
     <string name="notification_phishing_alert_content_description" msgid="494227305355958790">"Phishing-Warnung"</string>
     <string name="notification_work_profile_content_description" msgid="5296477955677725799">"Arbeitsprofil"</string>
     <string name="notification_alerted_content_description" msgid="6139691253611265992">"Gewarnt"</string>
-    <string name="notification_verified_content_description" msgid="6401483602782359391">"Bestätigt"</string>
+    <string name="notification_verified_content_description" msgid="6401483602782359391">"Verifiziert"</string>
     <string name="expand_button_content_description_collapsed" msgid="3873368935659010279">"Maximieren"</string>
     <string name="expand_button_content_description_expanded" msgid="7484217944948667489">"Minimieren"</string>
     <string name="expand_action_accessibility" msgid="1947657036871746627">"Maximierung ein-/auschalten"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 3f9cee1..2936a08 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1949,7 +1949,7 @@
     <string name="maximize_button_text" msgid="4258922519914732645">"بڑا کریں"</string>
     <string name="close_button_text" msgid="10603510034455258">"بند کریں"</string>
     <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
-    <string name="call_notification_answer_action" msgid="5999246836247132937">"جواب"</string>
+    <string name="call_notification_answer_action" msgid="5999246836247132937">"جواب دیں"</string>
     <string name="call_notification_answer_video_action" msgid="2086030940195382249">"ویڈیو"</string>
     <string name="call_notification_decline_action" msgid="3700345945214000726">"مسترد کریں"</string>
     <string name="call_notification_hang_up_action" msgid="9130720590159188131">"منقطع کر دیں"</string>
diff --git a/graphics/java/android/graphics/BLASTBufferQueue.java b/graphics/java/android/graphics/BLASTBufferQueue.java
index 6c1c2ee..36215ec 100644
--- a/graphics/java/android/graphics/BLASTBufferQueue.java
+++ b/graphics/java/android/graphics/BLASTBufferQueue.java
@@ -33,7 +33,7 @@
     private static native Surface nativeGetSurface(long ptr, boolean includeSurfaceControlHandle);
     private static native void nativeSetNextTransaction(long ptr, long transactionPtr);
     private static native void nativeUpdate(long ptr, long surfaceControl, long width, long height,
-            int format);
+            int format, long transactionPtr);
     private static native void nativeFlushShadowQueue(long ptr);
     private static native void nativeMergeWithNextTransaction(long ptr, long transactionPtr,
                                                               long frameNumber);
@@ -92,9 +92,15 @@
      * @param width The new width for the buffer.
      * @param height The new height for the buffer.
      * @param format The new format for the buffer.
+     * @param t Adds destination frame changes to the passed in transaction.
      */
+    public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format,
+            SurfaceControl.Transaction t) {
+        nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format, t.mNativeObject);
+    }
+
     public void update(SurfaceControl sc, int width, int height, @PixelFormat.Format int format) {
-        nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format);
+        nativeUpdate(mNativeObject, sc.mNativeObject, width, height, format, 0);
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index 4925209..872331c 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -67,7 +67,7 @@
 
     @NonNull RippleAnimationSession enter(Canvas canvas) {
         mStartTime = AnimationUtils.currentAnimationTimeMillis();
-        if (isHwAccelerated(canvas)) {
+        if (useRTAnimations(canvas)) {
             enterHardware((RecordingCanvas) canvas);
         } else {
             enterSoftware();
@@ -82,7 +82,7 @@
     }
 
     @NonNull RippleAnimationSession exit(Canvas canvas) {
-        if (isHwAccelerated(canvas)) exitHardware((RecordingCanvas) canvas);
+        if (useRTAnimations(canvas)) exitHardware((RecordingCanvas) canvas);
         else exitSoftware();
         return this;
     }
@@ -102,8 +102,12 @@
         return this;
     }
 
-    private boolean isHwAccelerated(Canvas canvas) {
-        return canvas.isHardwareAccelerated() && !mForceSoftware;
+    private boolean useRTAnimations(Canvas canvas) {
+        if (mForceSoftware) return false;
+        if (!canvas.isHardwareAccelerated()) return false;
+        RecordingCanvas hwCanvas = (RecordingCanvas) canvas;
+        if (hwCanvas.mNode == null || !hwCanvas.mNode.isAttached()) return false;
+        return true;
     }
 
     private void exitSoftware() {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index d3cff5c..7354c90 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -49,7 +49,9 @@
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.os.Build;
+import android.os.Looper;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.animation.AnimationUtils;
 import android.view.animation.LinearInterpolator;
 
@@ -113,6 +115,7 @@
  * @attr ref android.R.styleable#RippleDrawable_color
  */
 public class RippleDrawable extends LayerDrawable {
+    private static final String TAG = "RippleDrawable";
     /**
      * Radius value that specifies the ripple radius should be computed based
      * on the size of the ripple's container.
@@ -848,6 +851,10 @@
 
     private void startBackgroundAnimation() {
         mRunBackgroundAnimation = false;
+        if (Looper.myLooper() == null) {
+            Log.w(TAG, "Thread doesn't have a looper. Skipping animation.");
+            return;
+        }
         mBackgroundAnimation = ValueAnimator.ofFloat(mBackgroundOpacity, mTargetBackgroundOpacity);
         mBackgroundAnimation.setInterpolator(LINEAR_INTERPOLATOR);
         mBackgroundAnimation.setDuration(BACKGROUND_OPACITY_DURATION);
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 624b8b3..c2b6ffb 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -31,7 +31,7 @@
     <string name="accessibility_action_pip_stash" msgid="4060775037619702641">"స్టాచ్"</string>
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ఆన్‌స్టాచ్"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"స్క్రీన్ విభజనతో యాప్‌ పని చేయకపోవచ్చు."</string>
-    <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"అనువర్తనంలో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
+    <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"యాప్‌లో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ప్రత్యామ్నాయ డిస్‌ప్లేలో యాప్ పని చేయకపోవచ్చు."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ప్రత్యామ్నాయ డిస్‌ప్లేల్లో ప్రారంభానికి యాప్ మద్దతు లేదు."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"విభజన స్క్రీన్ విభాగిని"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
index 60074b8..7cf4fb7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedSettingsUtil.java
@@ -130,7 +130,7 @@
      */
     public boolean getSettingsTapsAppToExit(ContentResolver resolver, int userId) {
         return Settings.Secure.getIntForUser(resolver,
-                Settings.Secure.TAPS_APP_TO_EXIT, 0, userId) == 1;
+                Settings.Secure.TAPS_APP_TO_EXIT, 1, userId) == 1;
     }
 
     /**
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index c827932..cb887f2 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -38,6 +38,17 @@
 
     public abstract void updateRingerModeAffectedStreamsInternal();
 
+    /**
+     * Notify the UID of the currently active {@link android.service.voice.HotwordDetectionService}.
+     *
+     * <p>The caller is expected to take care of any performance implications, e.g. by using a
+     * background thread to call this method.</p>
+     *
+     * @param uid UID of the currently active service or {@link android.os.Process#INVALID_UID} if
+     *            none.
+     */
+    public abstract void setHotwordDetectionServiceUid(int uid);
+
     public abstract void setAccessibilityServiceUids(IntArray uids);
 
     /**
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 8012f03..69d1889 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1769,6 +1769,13 @@
     public static native int setAssistantUid(int uid);
 
     /**
+     * Communicate UID of the current {@link android.service.voice.HotwordDetectionService} to audio
+     * policy service.
+     * @hide
+     */
+    public static native int setHotwordDetectionServiceUid(int uid);
+
+    /**
      * @hide
      * Communicate UIDs of active accessibility services to audio policy service.
      */
diff --git a/mms/OWNERS b/mms/OWNERS
index befc320..7f05a2a 100644
--- a/mms/OWNERS
+++ b/mms/OWNERS
@@ -2,7 +2,6 @@
 
 tgunn@google.com
 breadley@google.com
-hallliu@google.com
 rgreenwalt@google.com
 amitmahajan@google.com
 fionaxu@google.com
@@ -10,7 +9,10 @@
 jminjie@google.com
 satk@google.com
 shuoq@google.com
-refuhoo@google.com
 nazaninb@google.com
 sarahchin@google.com
-dbright@google.com
\ No newline at end of file
+xiaotonj@google.com
+huiwang@google.com
+jayachandranc@google.com
+chinmayd@google.com
+amruthr@google.com
diff --git a/packages/CarrierDefaultApp/OWNERS b/packages/CarrierDefaultApp/OWNERS
index 5668840..0d23f05 100644
--- a/packages/CarrierDefaultApp/OWNERS
+++ b/packages/CarrierDefaultApp/OWNERS
@@ -1,7 +1,6 @@
 set noparent
 tgunn@google.com
 breadley@google.com
-hallliu@google.com
 rgreenwalt@google.com
 amitmahajan@google.com
 fionaxu@google.com
@@ -9,9 +8,11 @@
 jminjie@google.com
 satk@google.com
 shuoq@google.com
-refuhoo@google.com
 nazaninb@google.com
 sarahchin@google.com
-dbright@google.com
 xiaotonj@google.com
+huiwang@google.com
+jayachandranc@google.com
+chinmayd@google.com
+amruthr@google.com
 
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index a870026..4f74d24 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -489,7 +489,7 @@
     <string name="active_input_method_subtypes" msgid="4232680535471633046">"సక్రియ ఇన్‌పుట్ పద్ధతులు"</string>
     <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"సిస్టమ్ భాషలను ఉపయోగించు"</string>
     <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> యొక్క సెట్టింగ్‌లను తెరవడం విఫలమైంది"</string>
-    <string name="ime_security_warning" msgid="6547562217880551450">"ఈ ఇన్‌పుట్ పద్ధతి మీరు టైప్ చేసే మొత్తం వచనాన్ని అలాగే పాస్‌వర్డ్‌లు మరియు క్రెడిట్ కార్డు నంబర్‌ల వంటి వ్యక్తిగత డేటాను సేకరించగలదు. ఇది <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> అనువర్తనంలో అందించబడుతుంది. ఈ ఇన్‌పుట్ పద్ధతిని ఉపయోగించాలా?"</string>
+    <string name="ime_security_warning" msgid="6547562217880551450">"ఈ ఇన్‌పుట్ పద్ధతి మీరు టైప్ చేసే మొత్తం వచనాన్ని అలాగే పాస్‌వర్డ్‌లు మరియు క్రెడిట్ కార్డు నంబర్‌ల వంటి వ్యక్తిగత డేటాను సేకరించగలదు. ఇది <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> యాప్‌లో అందించబడుతుంది. ఈ ఇన్‌పుట్ పద్ధతిని ఉపయోగించాలా?"</string>
     <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"గమనిక: రీబూట్ చేసాక, మీరు మీ ఫోన్‌ను అన్‌లాక్ చేసే వరకు ఈ యాప్ ప్రారంభం కాదు"</string>
     <string name="ims_reg_title" msgid="8197592958123671062">"IMS నమోదు స్థితి"</string>
     <string name="ims_reg_status_registered" msgid="884916398194885457">"నమోదు చేయబడింది"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
index 1472980..e0339da 100644
--- a/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/enterprise/BiometricActionDisabledByAdminController.java
@@ -64,9 +64,9 @@
         return (dialog, which) -> {
             Log.d(TAG, "Positive button clicked, component: " + enforcedAdmin.component);
             final Intent intent = new Intent(ACTION_LEARN_MORE)
-                    .setComponent(enforcedAdmin.component)
                     .putExtra(EXTRA_SETTING_KEY, EXTRA_SETTING_VALUE)
-                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+                    .setPackage(enforcedAdmin.component.getPackageName());
             context.startActivity(intent);
         };
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index 79446e4..ed8d524 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -44,6 +44,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import androidx.annotation.RequiresApi;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -56,6 +58,7 @@
 /**
  * InfoMediaManager provide interface to get InfoMediaDevice list.
  */
+@RequiresApi(Build.VERSION_CODES.R)
 public class InfoMediaManager extends MediaManager {
 
     private static final String TAG = "InfoMediaManager";
@@ -145,9 +148,16 @@
     }
 
     private RoutingSessionInfo getRoutingSessionInfo() {
-        final List<RoutingSessionInfo> sessionInfos =
-                mRouterManager.getRoutingSessions(mPackageName);
+        return getRoutingSessionInfo(mPackageName);
+    }
 
+    private RoutingSessionInfo getRoutingSessionInfo(String packageName) {
+        final List<RoutingSessionInfo> sessionInfos =
+                mRouterManager.getRoutingSessions(packageName);
+
+        if (sessionInfos == null || sessionInfos.isEmpty()) {
+            return null;
+        }
         return sessionInfos.get(sessionInfos.size() - 1);
     }
 
@@ -367,33 +377,13 @@
     }
 
     boolean shouldDisableMediaOutput(String packageName) {
-        boolean shouldDisableMediaOutput = false;
         if (TextUtils.isEmpty(packageName)) {
             Log.w(TAG, "shouldDisableMediaOutput() package name is null or empty!");
-            return false;
+            return true;
         }
-        final List<MediaRoute2Info> infos = mRouterManager.getTransferableRoutes(packageName);
-        if (infos.size() == 1) {
-            final MediaRoute2Info info = infos.get(0);
-            final int deviceType = info.getType();
-            switch (deviceType) {
-                case TYPE_UNKNOWN:
-                case TYPE_REMOTE_TV:
-                case TYPE_REMOTE_SPEAKER:
-                case TYPE_GROUP:
-                    shouldDisableMediaOutput = true;
-                    break;
-                default:
-                    shouldDisableMediaOutput = false;
-                    break;
-            }
-        }
-        if (DEBUG) {
-            Log.d(TAG, "shouldDisableMediaOutput() MediaRoute2Info size : " + infos.size()
-                    + ", package name : " + packageName + ", shouldDisableMediaOutput : "
-                    + shouldDisableMediaOutput);
-        }
-        return shouldDisableMediaOutput;
+
+        // Disable when there is no transferable route
+        return mRouterManager.getTransferableRoutes(packageName).isEmpty();
     }
 
     @TargetApi(Build.VERSION_CODES.R)
@@ -456,7 +446,7 @@
     }
 
     private void buildAvailableRoutes() {
-        for (MediaRoute2Info route : mRouterManager.getTransferableRoutes(mPackageName)) {
+        for (MediaRoute2Info route : getAvailableRoutes(mPackageName)) {
             if (DEBUG) {
                 Log.d(TAG, "buildAvailableRoutes() route : " + route.getName() + ", volume : "
                         + route.getVolume() + ", type : " + route.getType());
@@ -465,6 +455,29 @@
         }
     }
 
+    private List<MediaRoute2Info> getAvailableRoutes(String packageName) {
+        final List<MediaRoute2Info> infos = new ArrayList<>();
+        RoutingSessionInfo routingSessionInfo = getRoutingSessionInfo(packageName);
+        if (routingSessionInfo != null) {
+            infos.addAll(mRouterManager.getSelectedRoutes(routingSessionInfo));
+        }
+        final List<MediaRoute2Info> transferableRoutes =
+                mRouterManager.getTransferableRoutes(packageName);
+        for (MediaRoute2Info transferableRoute : transferableRoutes) {
+            boolean alreadyAdded = false;
+            for (MediaRoute2Info mediaRoute2Info : infos) {
+                if (TextUtils.equals(transferableRoute.getId(), mediaRoute2Info.getId())) {
+                    alreadyAdded = true;
+                    break;
+                }
+            }
+            if (!alreadyAdded) {
+                infos.add(transferableRoute);
+            }
+        }
+        return infos;
+    }
+
     @VisibleForTesting
     void addMediaDevice(MediaRoute2Info route) {
         final int deviceType = route.getType();
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index a8da2c0..22001c9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -22,11 +22,13 @@
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
 import android.media.RoutingSessionInfo;
+import android.os.Build;
 import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.annotation.IntDef;
 import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.bluetooth.A2dpProfile;
@@ -49,6 +51,7 @@
 /**
  * LocalMediaManager provide interface to get MediaDevice list and transfer media to MediaDevice.
  */
+@RequiresApi(Build.VERSION_CODES.R)
 public class LocalMediaManager implements BluetoothCallback {
     private static final Comparator<MediaDevice> COMPARATOR = Comparator.naturalOrder();
     private static final String TAG = "LocalMediaManager";
diff --git a/packages/SystemUI/res/anim/fp_to_unlock.xml b/packages/SystemUI/res/anim/fp_to_unlock.xml
index a348208..a5f75b6 100644
--- a/packages/SystemUI/res/anim/fp_to_unlock.xml
+++ b/packages/SystemUI/res/anim/fp_to_unlock.xml
@@ -19,10 +19,10 @@
       <group android:name="_R_G">
         <group android:name="_R_G_L_1_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5">
           <group android:name="_R_G_L_1_G" android:translateX="30.75" android:translateY="25.75">
-            <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " />
-            <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " />
-            <path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " />
-            <path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " />
+            <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M27.52 38.98 C26.49,39.95 25.29,40.73 23.98,41.29 C23.17,41.65 22.31,41.91 21.41,42.07 C20.74,42.19 20.05,42.25 19.34,42.25 C18.44,42.25 17.56,42.15 16.72,41.96 C15.93,41.77 15.16,41.51 14.43,41.18 C13.23,40.63 12.13,39.88 11.16,38.98 " />
+            <path android:name="_R_G_L_1_G_D_1_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M8.64 34.07 C7.89,31.97 7.89,29.85 7.89,29.85 C7.89,24.05 12.81,19.34 19.34,19.34 C25.87,19.34 30.8,24.05 30.8,29.85 C30.8,29.85 30.8,30.16 30.8,30.16 C30.8,32.32 29.04,34.07 26.89,34.07 C25.28,34.07 23.86,33.1 23.27,31.61 C23.27,31.61 21.96,28.34 21.96,28.34 C21.37,26.85 19.93,25.89 18.34,25.89 C16.18,25.89 14.43,27.64 14.43,29.8 C14.43,31.42 14.87,32.99 15.68,34.36 C16.22,35.26 16.93,36.08 17.77,36.75 C17.77,36.75 18.52,37.34 18.52,37.34 " />
+            <path android:name="_R_G_L_1_G_D_2_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M6.25 19.34 C7.48,17.3 9.46,15.58 11.9,14.42 C12.93,13.94 14.03,13.55 15.2,13.27 C16.51,12.96 17.9,12.8 19.34,12.8 C20.77,12.8 22.14,12.96 23.45,13.26 C24.9,13.6 26.26,14.12 27.48,14.78 C29.6,15.92 31.32,17.5 32.43,19.34 " />
+            <path android:name="_R_G_L_1_G_D_3_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M9.52 8.7 C10.98,7.91 12.58,7.28 14.28,6.86 C15.89,6.46 17.58,6.25 19.34,6.25 C21.06,6.25 22.72,6.45 24.3,6.83 C26.04,7.25 27.67,7.89 29.16,8.7 " />
           </group>
         </group>
         <group android:name="_R_G_L_0_G_N_7_T_0" android:translateX="-27" android:translateY="-17.5">
diff --git a/packages/SystemUI/res/anim/lock_to_unlock.xml b/packages/SystemUI/res/anim/lock_to_unlock.xml
index ec51c01..76f7a05 100644
--- a/packages/SystemUI/res/anim/lock_to_unlock.xml
+++ b/packages/SystemUI/res/anim/lock_to_unlock.xml
@@ -21,7 +21,7 @@
           <group android:name="_R_G_L_2_G_N_10_T_1" android:translateX="50.25" android:translateY="61">
             <group android:name="_R_G_L_2_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5">
               <group android:name="_R_G_L_2_G" android:translateX="-0.375" android:translateY="-22.375">
-                <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " />
+                <path android:name="_R_G_L_2_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " />
               </group>
             </group>
           </group>
@@ -30,7 +30,7 @@
           <group android:name="_R_G_L_1_G_N_10_T_1" android:translateX="50.25" android:translateY="61">
             <group android:name="_R_G_L_1_G_N_10_T_0" android:translateX="-13.75" android:translateY="-7.5">
               <group android:name="_R_G_L_1_G" android:translateX="5" android:translateY="-22.5">
-                <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2.5" android:strokeAlpha="1" android:pathData=" M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " />
+                <path android:name="_R_G_L_1_G_D_0_P_0" android:strokeColor="#b7f29f" android:strokeLineCap="round" android:strokeLineJoin="round" android:strokeWidth="2" android:strokeAlpha="1" android:pathData=" M2.5 15 C2.5,15 2.5,8.61 2.5,8.61 C2.5,5.24 5.3,2.5 8.75,2.5 C12.2,2.5 15,5.24 15,8.61 C15,8.61 15,15 15,15 " />
               </group>
             </group>
           </group>
diff --git a/packages/SystemUI/res/drawable/ic_unlock.xml b/packages/SystemUI/res/drawable/ic_unlock.xml
index c3b3469..46023e6 100644
--- a/packages/SystemUI/res/drawable/ic_unlock.xml
+++ b/packages/SystemUI/res/drawable/ic_unlock.xml
@@ -21,7 +21,7 @@
             android:strokeColor="#FF000000"
             android:strokeLineCap="round"
             android:strokeLineJoin="round"
-            android:strokeWidth="2.5"
+            android:strokeWidth="2"
             android:pathData="M4.75 15 C4.75,15 23.25,15 23.25,15 C24.35,15 25.25,15.9 25.25,17 C25.25,17 25.25,33 25.25,33 C25.25,34.1 24.35,35 23.25,35 C23.25,35 4.75,35 4.75,35 C3.65,35 2.75,34.1 2.75,33 C2.75,33 2.75,17 2.75,17 C2.75,15.9 3.65,15 4.75,15c " />
     </group>
     <group android:translateX="14" android:translateY="13.5">
@@ -29,7 +29,7 @@
             android:strokeColor="#FF000000"
             android:strokeLineCap="round"
             android:strokeLineJoin="round"
-            android:strokeWidth="2.5"
+            android:strokeWidth="2"
             android:pathData="M27.19 14.81 C27.19,14.81 27.19,8.3 27.19,8.3 C27.19,4.92 24.44,2.88 21.19,2.75 C17.74,2.62 15,4.74 15,8.11 C15,8.11 15,15 15,15 " />
     </group>
     <group android:translateX="20" android:translateY="35.75">
diff --git a/packages/SystemUI/res/layout/keyguard_status_bar.xml b/packages/SystemUI/res/layout/keyguard_status_bar.xml
index 2789ed1..eb76382 100644
--- a/packages/SystemUI/res/layout/keyguard_status_bar.xml
+++ b/packages/SystemUI/res/layout/keyguard_status_bar.xml
@@ -30,6 +30,7 @@
         android:id="@+id/status_icon_area"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
+        android:paddingEnd="@dimen/system_icons_keyguard_padding_end"
         android:paddingTop="@dimen/status_bar_padding_top"
         android:layout_alignParentEnd="true"
         android:gravity="center_vertical|end" >
@@ -38,12 +39,10 @@
             android:layout_height="match_parent"
             android:layout_weight="1"
             android:layout_marginStart="@dimen/system_icons_super_container_margin_start"
-            android:gravity="center_vertical|end"
-            android:paddingEnd="@dimen/system_icons_keyguard_padding_end" >
+            android:gravity="center_vertical|end">
             <include layout="@layout/system_icons" />
         </FrameLayout>
 
-
         <ImageView android:id="@+id/multi_user_avatar"
             android:layout_width="@dimen/multi_user_avatar_keyguard_size"
             android:layout_height="@dimen/multi_user_avatar_keyguard_size"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index b0f1f48..6d5be30 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -68,7 +68,7 @@
             android:id="@+id/lock_icon"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:padding="48px"
+            android:padding="@dimen/lock_icon_padding"
             android:layout_gravity="center"
             android:scaleType="centerCrop"/>
     </com.android.keyguard.LockIconView>
diff --git a/packages/SystemUI/res/layout/udfps_keyguard_view.xml b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
index 18517906..a9eb27a 100644
--- a/packages/SystemUI/res/layout/udfps_keyguard_view.xml
+++ b/packages/SystemUI/res/layout/udfps_keyguard_view.xml
@@ -34,7 +34,7 @@
         android:id="@+id/udfps_aod_fp"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:padding="48px"
+        android:padding="@dimen/lock_icon_padding"
         android:layout_gravity="center"
         android:scaleType="centerCrop"
         app:lottie_autoPlay="false"
@@ -46,7 +46,7 @@
         android:id="@+id/udfps_lockscreen_fp"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:padding="48px"
+        android:padding="@dimen/lock_icon_padding"
         android:layout_gravity="center"
         android:scaleType="centerCrop"
         app:lottie_autoPlay="false"
diff --git a/packages/SystemUI/res/raw/udfps_aod_fp.json b/packages/SystemUI/res/raw/udfps_aod_fp.json
index 3247fe7..3b273ff 100644
--- a/packages/SystemUI/res/raw/udfps_aod_fp.json
+++ b/packages/SystemUI/res/raw/udfps_aod_fp.json
@@ -164,7 +164,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -526,7 +526,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -829,7 +829,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -1132,7 +1132,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -1507,7 +1507,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -1882,7 +1882,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -2257,7 +2257,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
@@ -2560,7 +2560,7 @@
               },
               "w":{
                 "a":0,
-                "k":1,
+                "k":1.3,
                 "ix":5
               },
               "lc":2,
diff --git a/packages/SystemUI/res/raw/udfps_lockscreen_fp.json b/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
index a25a475..a30a03a 100644
--- a/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
+++ b/packages/SystemUI/res/raw/udfps_lockscreen_fp.json
@@ -1 +1 @@
-{"v":"5.7.8","fr":60,"ip":0,"op":46,"w":46,"h":65,"nm":"fingerprint_build_on","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Fingerprint_20210701 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[23.091,32.5,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.949000000954,0.624000012875,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-1.636],[4.642,0.681],[2.07,1.453],[-0.001,1.636],[-2.621,1.341],[-4.909,0.563],[-8.182,-1.636]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2.5]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[{"tm":210,"cm":"2","dr":0},{"tm":255,"cm":"1","dr":0}]}
\ No newline at end of file
+{"v":"5.7.8","fr":60,"ip":0,"op":46,"w":46,"h":65,"nm":"fingerprint_build_on","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Fingerprint_20210701 Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[23.091,32.5,0],"ix":2,"l":2},"a":{"a":0,"k":[19.341,24.25,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.701,0.42],[-1.757,0],[-1.577,-0.381],[-1.485,-0.816]],"o":[[1.455,-0.799],[1.608,-0.397],[1.719,0],[1.739,0.42],[0,0]],"v":[[-9.818,1.227],[-5.064,-0.618],[0,-1.227],[4.96,-0.643],[9.818,1.227]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,7.477],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Top","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.446,1.161],[-1.168,0.275],[-1.439,0],[-1.301,-0.304],[-1.225,-0.66],[-1.11,-1.844]],"o":[[1.23,-2.044],[1.024,-0.486],[1.312,-0.31],[1.425,0],[1.454,0.34],[2.122,1.143],[0,0]],"v":[[-13.091,3.273],[-7.438,-1.646],[-4.14,-2.797],[0,-3.273],[4.104,-2.805],[8.141,-1.29],[13.091,3.273]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,16.069],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Mid Top","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-6.53,0],[0,-5.793],[0,0],[2.159,0],[0.59,1.489],[0,0],[1.587,0],[0,-2.16],[-0.81,-1.363],[-0.844,-0.674],[0,0]],"o":[[-0.753,-2.095],[0,-5.793],[6.529,0],[0,0],[0,2.16],[-1.604,0],[0,0],[-0.589,-1.489],[-2.161,0],[0,1.62],[0.54,0.909],[0,0],[0,0]],"v":[[-10.702,5.728],[-11.454,1.506],[0.001,-9],[11.454,1.506],[11.454,1.817],[7.544,5.728],[3.926,3.273],[2.618,0],[-0.997,-2.454],[-4.91,1.457],[-3.657,6.014],[-1.57,8.412],[-0.818,9]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999994755,0.949000000954,0.624000012875,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,28.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Inside to dot ","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.307,-0.561],[0.894,-0.16],[0.706,0],[0.844,0.193],[0.728,0.334],[0.967,0.901]],"o":[[-1.038,0.967],[-0.817,0.351],[-0.673,0.12],[-0.9,0],[-0.794,-0.182],[-1.203,-0.551],[0,0]],"v":[[8.182,-1.636],[4.642,0.681],[2.07,1.453],[-0.001,1.636],[-2.621,1.341],[-4.909,0.563],[-8.182,-1.636]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.717999985639,0.948999980852,0.62400004069,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":1,"k":[{"i":{"x":[0],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":24,"s":[2]}],"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[19.341,40.614],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Bottom","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[{"tm":210,"cm":"2","dr":0},{"tm":255,"cm":"1","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 7d00c5b..e17f032e 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -799,7 +799,7 @@
       <item quantity="other">%d分</item>
       <item quantity="one">%d分</item>
     </plurals>
-    <string name="battery_panel_title" msgid="5931157246673665963">"電池の使用状況"</string>
+    <string name="battery_panel_title" msgid="5931157246673665963">"バッテリーの使用状況"</string>
     <string name="battery_detail_charging_summary" msgid="8821202155297559706">"充電中はバッテリー セーバーは利用できません"</string>
     <string name="battery_detail_switch_title" msgid="6940976502957380405">"バッテリー セーバー"</string>
     <string name="battery_detail_switch_summary" msgid="3668748557848025990">"パフォーマンスとバックグラウンド データを制限します"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index f62d9da..8a26ed3 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -707,11 +707,11 @@
     <string name="tuner_full_importance_settings" msgid="1388025816553459059">"Эскертмелерди башкаруу каражаттары"</string>
     <string name="tuner_full_importance_settings_on" msgid="917981436602311547">"Күйүк"</string>
     <string name="tuner_full_importance_settings_off" msgid="5580102038749680829">"Өчүк"</string>
-    <string name="power_notification_controls_description" msgid="1334963837572708952">"Бул функциянын жардамы менен, ар бир колдонмо үчүн билдирменин маанилүүлүгүн 0дон 5ке чейин бааласаңыз болот. \n\n"<b>"5-деңгээл"</b>" \n- Билдирмелер тизмесинин өйдө жагында көрсөтүлөт \n- Билдирмелер толук экранда көрсөтүлөт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"4-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"3-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n\n"<b>"2-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n\n"<b>"1-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n- Кулпуланган экрандан жана абал тилкесинен жашырылат \n- Билдирмелер тизмесинин ылдый жагында көрсөтүлөт \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык билдирмелер бөгөттөлөт"</string>
+    <string name="power_notification_controls_description" msgid="1334963837572708952">"Бул функциянын жардамы менен, ар бир колдонмо үчүн билдирменин маанилүүлүгүн 0дон 5ке чейин бааласаңыз болот. \n\n"<b>"5-деңгээл"</b>" \n- Билдирмелер тизмесинин өйдө жагында көрүнөт \n- Билдирмелер толук экранда көрүнөт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"4-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге уруксат берилет \n\n"<b>"3-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n\n"<b>"2-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n\n"<b>"1-деңгээл"</b>" \n- Билдирмелер толук экранда көрүнбөйт \n- Калкып чыгуучу билдирмелерге тыюу салынат \n- Эч качан үн чыкпайт же дирилдебейт \n- Кулпуланган экрандан жана абал тилкесинен жашырылат \n- Билдирмелер тизмесинин ылдый жагында көрүнөт \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык билдирмелер бөгөттөлөт"</string>
     <string name="notification_header_default_channel" msgid="225454696914642444">"Билдирмелер"</string>
     <string name="notification_channel_disabled" msgid="928065923928416337">"Мындан ары бул билдирмелер сизге көрүнбөйт"</string>
     <string name="notification_channel_minimized" msgid="6892672757877552959">"Бул билдирмелер кичирейтилет"</string>
-    <string name="notification_channel_silenced" msgid="1995937493874511359">"Бул билдирмелер үнсүз көрсөтүлөт"</string>
+    <string name="notification_channel_silenced" msgid="1995937493874511359">"Бул билдирмелер үнсүз көрүнөт"</string>
     <string name="notification_channel_unsilenced" msgid="94878840742161152">"Бул билдирмелер тууралуу кабарлап турабыз"</string>
     <string name="inline_blocking_helper" msgid="2891486013649543452">"Адатта мындай билдирмелерди өткөрүп жибересиз. \nАлар көрүнө берсинби?"</string>
     <string name="inline_done_button" msgid="6043094985588909584">"Бүттү"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index c503ebd..40ceb59 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -452,8 +452,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"खोल्न पुनः ट्याप गर्नुहोस्"</string>
     <string name="tap_again" msgid="1315420114387908655">"फेरि ट्याप गर्नुहोस्"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"खोल्न माथितिर स्वाइप गर्नुहोस्"</string>
-    <!-- no translation found for keyguard_unlock_press (8488350566398524740) -->
-    <skip />
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"अनलक गर्न प्रेस गर्नुहोस्"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"फेरि प्रयास गर्न माथितिर स्वाइप गर्नुहोस्"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"NFC प्रयोग गर्न स्क्रिन अनलक गर्नुहोस्"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"यो डिभाइस तपाईंको सङ्गठनको स्वामित्वमा छ"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 6845b5b..a948fae 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -452,8 +452,7 @@
     <string name="notification_tap_again" msgid="4477318164947497249">"Trokit përsëri për ta hapur"</string>
     <string name="tap_again" msgid="1315420114387908655">"Trokit sërish"</string>
     <string name="keyguard_unlock" msgid="8031975796351361601">"Rrëshqit lart për ta hapur"</string>
-    <!-- no translation found for keyguard_unlock_press (8488350566398524740) -->
-    <skip />
+    <string name="keyguard_unlock_press" msgid="8488350566398524740">"Shtyp për të hapur"</string>
     <string name="keyguard_retry" msgid="886802522584053523">"Rrëshqit lart për të provuar përsëri"</string>
     <string name="require_unlock_for_nfc" msgid="1305686454823018831">"Shkyçe për të përdorur NFC-në"</string>
     <string name="do_disclosure_generic" msgid="4896482821974707167">"Kjo pajisje i përket organizatës sate"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 34f8503..0e02ad0 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -529,6 +529,9 @@
     <!-- Gravity for the notification panel -->
     <integer name="notification_panel_layout_gravity">0x31</integer><!-- center_horizontal|top -->
 
+    <!-- Padding for the lock icon on the keyguard. In pixels - should not scale with display size. -->
+    <dimen name="lock_icon_padding">48px</dimen>
+
     <!-- Height of the carrier/wifi name label -->
     <dimen name="carrier_label_height">24dp</dimen>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 04e5dd1..a670216 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -438,6 +438,8 @@
     <string name="fingerprint_dialog_use_fingerprint">Use your fingerprint to continue</string>
     <!-- Message shown to ask the user to use screenlock to continue.[CHAR LIMIT=NONE] -->
     <string name="fingerprint_dialog_cant_recognize_fp_use_screenlock">Can\u2019t recognize fingerprint. Use screen lock instead.</string>
+    <!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
+    <string name="keyguard_face_failed_use_fp">@string/fingerprint_dialog_use_fingerprint_instead</string>
 
     <!-- Message shown when the system-provided face dialog is shown, asking for authentication [CHAR LIMIT=30] -->
     <string name="face_dialog_looking_for_face">Looking for you\u2026</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 23d6ebc..0bb5b1c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -347,13 +347,16 @@
     private static final int HAL_ERROR_RETRY_TIMEOUT = 500; // ms
     private static final int HAL_ERROR_RETRY_MAX = 20;
 
-    private final Runnable mCancelNotReceived = new Runnable() {
-        @Override
-        public void run() {
-            Log.w(TAG, "Cancel not received, transitioning to STOPPED");
-            mFingerprintRunningState = mFaceRunningState = BIOMETRIC_STATE_STOPPED;
-            updateBiometricListeningState();
-        }
+    private final Runnable mFpCancelNotReceived = () -> {
+        Log.e(TAG, "Fp cancellation not received, transitioning to STOPPED");
+        mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
+        updateFingerprintListeningState();
+    };
+
+    private final Runnable mFaceCancelNotReceived = () -> {
+        Log.e(TAG, "Face cancellation not received, transitioning to STOPPED");
+        mFaceRunningState = BIOMETRIC_STATE_STOPPED;
+        updateFaceListeningState();
     };
 
     private final Handler mHandler;
@@ -791,19 +794,19 @@
 
     private void handleFingerprintError(int msgId, String errString) {
         Assert.isMainThread();
-        if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED && mHandler.hasCallbacks(
-                mCancelNotReceived)) {
-            mHandler.removeCallbacks(mCancelNotReceived);
+        if (mHandler.hasCallbacks(mFpCancelNotReceived)) {
+            mHandler.removeCallbacks(mFpCancelNotReceived);
         }
 
+        // Error is always the end of authentication lifecycle.
+        mFingerprintCancelSignal = null;
+
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
                 && mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
             updateFingerprintListeningState();
         } else {
             setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
-            mFingerprintCancelSignal = null;
-            mFaceCancelSignal = null;
         }
 
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
@@ -905,6 +908,7 @@
 
     private void handleFaceAuthFailed() {
         Assert.isMainThread();
+        mFaceCancelSignal = null;
         setFaceRunningState(BIOMETRIC_STATE_STOPPED);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -983,10 +987,13 @@
     private void handleFaceError(int msgId, String errString) {
         Assert.isMainThread();
         if (DEBUG_FACE) Log.d(TAG, "Face error received: " + errString);
-        if (msgId == FaceManager.FACE_ERROR_CANCELED && mHandler.hasCallbacks(mCancelNotReceived)) {
-            mHandler.removeCallbacks(mCancelNotReceived);
+        if (mHandler.hasCallbacks(mFaceCancelNotReceived)) {
+            mHandler.removeCallbacks(mFaceCancelNotReceived);
         }
 
+        // Error is always the end of authentication lifecycle
+        mFaceCancelSignal = null;
+
         if (msgId == FaceManager.FACE_ERROR_CANCELED
                 && mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
@@ -2368,6 +2375,14 @@
     }
 
     private void startListeningForFingerprint() {
+        final int userId = getCurrentUser();
+        final boolean unlockPossible = isUnlockWithFingerprintPossible(userId);
+        if (mFingerprintCancelSignal != null) {
+            Log.e(TAG, "Cancellation signal is not null, high chance of bug in fp auth lifecycle"
+                    + " management. FP state: " + mFingerprintRunningState
+                    + ", unlockPossible: " + unlockPossible);
+        }
+
         if (mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING) {
             setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);
             return;
@@ -2377,11 +2392,8 @@
             return;
         }
         if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
-        int userId = getCurrentUser();
-        if (isUnlockWithFingerprintPossible(userId)) {
-            if (mFingerprintCancelSignal != null) {
-                mFingerprintCancelSignal.cancel();
-            }
+
+        if (unlockPossible) {
             mFingerprintCancelSignal = new CancellationSignal();
 
             if (isEncryptedOrLockdown(userId)) {
@@ -2397,6 +2409,14 @@
     }
 
     private void startListeningForFace() {
+        final int userId = getCurrentUser();
+        final boolean unlockPossible = isUnlockWithFacePossible(userId);
+        if (mFaceCancelSignal != null) {
+            Log.e(TAG, "Cancellation signal is not null, high chance of bug in face auth lifecycle"
+                    + " management. Face state: " + mFaceRunningState
+                    + ", unlockPossible: " + unlockPossible);
+        }
+
         if (mFaceRunningState == BIOMETRIC_STATE_CANCELLING) {
             setFaceRunningState(BIOMETRIC_STATE_CANCELLING_RESTARTING);
             return;
@@ -2405,11 +2425,8 @@
             return;
         }
         if (DEBUG) Log.v(TAG, "startListeningForFace(): " + mFaceRunningState);
-        int userId = getCurrentUser();
-        if (isUnlockWithFacePossible(userId)) {
-            if (mFaceCancelSignal != null) {
-                mFaceCancelSignal.cancel();
-            }
+
+        if (unlockPossible) {
             mFaceCancelSignal = new CancellationSignal();
 
             // This would need to be updated for multi-sensor devices
@@ -2461,9 +2478,8 @@
             if (mFingerprintCancelSignal != null) {
                 mFingerprintCancelSignal.cancel();
                 mFingerprintCancelSignal = null;
-                if (!mHandler.hasCallbacks(mCancelNotReceived)) {
-                    mHandler.postDelayed(mCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
-                }
+                mHandler.removeCallbacks(mFpCancelNotReceived);
+                mHandler.postDelayed(mFpCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
             }
             setFingerprintRunningState(BIOMETRIC_STATE_CANCELLING);
         }
@@ -2478,9 +2494,8 @@
             if (mFaceCancelSignal != null) {
                 mFaceCancelSignal.cancel();
                 mFaceCancelSignal = null;
-                if (!mHandler.hasCallbacks(mCancelNotReceived)) {
-                    mHandler.postDelayed(mCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
-                }
+                mHandler.removeCallbacks(mFaceCancelNotReceived);
+                mHandler.postDelayed(mFaceCancelNotReceived, DEFAULT_CANCEL_SIGNAL_TIMEOUT);
             }
             setFaceRunningState(BIOMETRIC_STATE_CANCELLING);
         }
@@ -2842,6 +2857,11 @@
             mSecureCameraLaunched = false;
         }
 
+        if (mKeyguardBypassController != null) {
+            // LS visibility has changed, so reset deviceEntryIntent
+            mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
+        }
+
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index d122610..d46426a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -23,7 +23,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
@@ -68,8 +67,6 @@
     private float mBurnInProgress;
     private float mInterpolatedDarkAmount;
 
-    private ValueAnimator mHintAnimator;
-
     public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
         mFingerprintDrawable = new UdfpsFpDrawable(context);
@@ -94,9 +91,6 @@
                 new KeyPath("**"), LottieProperty.COLOR_FILTER,
                 frameInfo -> new PorterDuffColorFilter(mTextColorPrimary, PorterDuff.Mode.SRC_ATOP)
         );
-
-        mHintAnimator = ObjectAnimator.ofFloat(mLockScreenFp, "progress", 1f, 0f, 1f);
-        mHintAnimator.setDuration(4000);
     }
 
     @Override
@@ -183,19 +177,11 @@
     }
 
     void onDozeAmountChanged(float linear, float eased) {
-        mHintAnimator.cancel();
         mInterpolatedDarkAmount = eased;
         updateAlpha();
         updateBurnInOffsets();
     }
 
-    void animateHint() {
-        if (!isShadeLocked() && !mUdfpsRequested && mAlpha == 255
-                && mLockScreenFp.isVisibleToUser()) {
-            mHintAnimator.start();
-        }
-    }
-
     /**
      * Animates in the bg protection circle behind the fp icon to highlight the icon.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 58f1254..4896305 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -20,14 +20,10 @@
 
 import android.annotation.NonNull;
 import android.content.res.Configuration;
-import android.hardware.biometrics.BiometricSourceType;
 import android.util.MathUtils;
 import android.view.MotionEvent;
 
-import androidx.annotation.Nullable;
-
 import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.R;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -46,14 +42,8 @@
 
 /**
  * Class that coordinates non-HBM animations during keyguard authentication.
- *
- * Highlights the udfps icon when:
- * - Face authentication has failed
- * - Face authentication has been run for > 2 seconds
  */
 public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<UdfpsKeyguardView> {
-    private static final long AFTER_FACE_AUTH_HINT_DELAY = 2000;
-
     @NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
     @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @NonNull private final DelayableExecutor mExecutor;
@@ -62,12 +52,10 @@
     @NonNull private final ConfigurationController mConfigurationController;
     @NonNull private final UdfpsController mUdfpsController;
 
-    @Nullable private Runnable mCancelDelayedHintRunnable;
     private boolean mShowingUdfpsBouncer;
     private boolean mUdfpsRequested;
     private boolean mQsExpanded;
     private boolean mFaceDetectRunning;
-    private boolean mHintShown;
     private int mStatusBarState;
     private float mTransitionToFullShadeProgress;
     private float mLastDozeAmount;
@@ -110,10 +98,6 @@
     @Override
     protected void onViewAttached() {
         super.onViewAttached();
-        mHintShown = false;
-        mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
-        updateFaceDetectRunning(mKeyguardUpdateMonitor.isFaceDetectionRunning());
-
         final float dozeAmount = mStatusBarStateController.getDozeAmount();
         mLastDozeAmount = dozeAmount;
         mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
@@ -136,7 +120,6 @@
     @Override
     protected void onViewDetached() {
         super.onViewDetached();
-        mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
         mFaceDetectRunning = false;
 
         mStatusBarStateController.removeCallback(mStateListener);
@@ -146,11 +129,6 @@
         if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
             mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
         }
-
-        if (mCancelDelayedHintRunnable != null) {
-            mCancelDelayedHintRunnable.run();
-            mCancelDelayedHintRunnable = null;
-        }
     }
 
     @Override
@@ -249,36 +227,6 @@
         }
     }
 
-    private void cancelDelayedHint() {
-        if (mCancelDelayedHintRunnable != null) {
-            mCancelDelayedHintRunnable.run();
-            mCancelDelayedHintRunnable = null;
-        }
-    }
-
-    private void updateFaceDetectRunning(boolean running) {
-        if (mFaceDetectRunning == running) {
-            return;
-        }
-
-        // show udfps hint a few seconds after face auth started running
-        if (!mFaceDetectRunning && running && !mHintShown && mCancelDelayedHintRunnable == null) {
-            // Face detect started running, show udfps hint after a delay
-            mCancelDelayedHintRunnable = mExecutor.executeDelayed(() -> showHint(false),
-                    AFTER_FACE_AUTH_HINT_DELAY);
-        }
-
-        mFaceDetectRunning = running;
-    }
-
-    private void showHint(boolean forceShow) {
-        cancelDelayedHint();
-        if (!mHintShown || forceShow) {
-            mHintShown = true;
-            mView.animateHint();
-        }
-    }
-
     /**
      * Set the progress we're currently transitioning to the full shade. 0.0f means we're not
      * transitioning yet, while 1.0f means we've fully dragged down.
@@ -318,39 +266,6 @@
         }
     };
 
-    private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
-            new KeyguardUpdateMonitorCallback() {
-                public void onBiometricRunningStateChanged(boolean running,
-                        BiometricSourceType biometricSourceType) {
-                    if (biometricSourceType == BiometricSourceType.FACE) {
-                        updateFaceDetectRunning(running);
-                    }
-                }
-
-                public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
-                    if (biometricSourceType == BiometricSourceType.FACE) {
-                        // show udfps hint when face auth fails
-                        showHint(true);
-                    }
-                }
-
-                public void onBiometricError(int msgId, String errString,
-                        BiometricSourceType biometricSourceType) {
-                    if (biometricSourceType == BiometricSourceType.FACE) {
-                        // show udfps hint when face auth fails
-                        showHint(true);
-                    }
-                }
-
-                public void onBiometricAuthenticated(int userId,
-                        BiometricSourceType biometricSourceType, boolean isStrongBiometric) {
-                    if (biometricSourceType == BiometricSourceType.FACE) {
-                        // cancel delayed hint if face auth succeeded
-                        cancelDelayedHint();
-                    }
-                }
-            };
-
     private final StatusBarKeyguardViewManager.AlternateAuthInterceptor mAlternateAuthInterceptor =
             new StatusBarKeyguardViewManager.AlternateAuthInterceptor() {
                 @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 23c4413..b2db86f 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -115,6 +115,7 @@
         mSecureSettings = secureSettings;
         mCallback = callback;
         mProximitySensor = proximitySensor;
+        mProximitySensor.setTag(TAG);
         mSelectivelyRegisterProxSensors = dozeParameters.getSelectivelyRegisterSensorsUsingProx();
         mListeningProxSensors = !mSelectivelyRegisterProxSensors;
         mScreenOffUdfpsEnabled =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 84cb12c..c20ae0b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2759,7 +2759,10 @@
 
         // Don't hide the keyguard due to a doze change if there's a lock pending, because we're
         // just going to show it again.
-        if (mShowing || !mPendingLock) {
+        // If the device is not capable of controlling the screen off animation, SysUI needs to
+        // update lock screen state in ATMS here, otherwise ATMS tries to resume activities when
+        // enabling doze state.
+        if (mShowing || !mPendingLock || !mDozeParameters.canControlUnlockedScreenOff()) {
             setShowingLocked(mShowing);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index ce1066e..1bd3664 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -268,7 +268,7 @@
     }
 
     @Override
-    public void setExpansion(float expansion) {
+    public void setExpansion(float expansion, float proposedTranslation) {
         mLastExpansion = expansion;
         updateSelected();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index c9230d6..1c841ec 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -498,11 +498,13 @@
                             : headerTranslation);
         }
         int currentHeight = getView().getHeight();
-        mLastHeaderTranslation = headerTranslation;
-        if (expansion == mLastQSExpansion && mLastKeyguardAndExpanded == onKeyguardAndExpanded
-                && mLastViewHeight == currentHeight) {
+        if (expansion == mLastQSExpansion
+                && mLastKeyguardAndExpanded == onKeyguardAndExpanded
+                && mLastViewHeight == currentHeight
+                && mLastHeaderTranslation == headerTranslation) {
             return;
         }
+        mLastHeaderTranslation = headerTranslation;
         mLastQSExpansion = expansion;
         mLastKeyguardAndExpanded = onKeyguardAndExpanded;
         mLastViewHeight = currentHeight;
@@ -522,8 +524,8 @@
         }
         mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
         mQSPanelController.setRevealExpansion(expansion);
-        mQSPanelController.getTileLayout().setExpansion(expansion);
-        mQuickQSPanelController.getTileLayout().setExpansion(expansion);
+        mQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
+        mQuickQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
         mQSPanelScrollView.setTranslationY(translationScaleY * heightDiff);
         if (fullyCollapsed) {
             mQSPanelScrollView.setScrollY(0);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 1b4ee73..cde80e66 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -742,7 +742,7 @@
         void setListening(boolean listening, UiEventLogger uiEventLogger);
 
         /**
-         * Set the minimum number of rows to show
+         * Sets the minimum number of rows to show
          *
          * @param minRows the minimum.
          */
@@ -751,7 +751,7 @@
         }
 
         /**
-         * Set the max number of columns to show
+         * Sets the max number of columns to show
          *
          * @param maxColumns the maximum
          *
@@ -761,7 +761,10 @@
             return false;
         }
 
-        default void setExpansion(float expansion) {}
+        /**
+         * Sets the expansion value and proposedTranslation to panel.
+         */
+        default void setExpansion(float expansion, float proposedTranslation) {}
 
         int getNumVisibleTiles();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 985943b..c5bfe97 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -177,6 +177,8 @@
 
     static class QQSSideLabelTileLayout extends SideLabelTileLayout {
 
+        private boolean mLastSelected;
+
         QQSSideLabelTileLayout(Context context) {
             super(context, null);
             setClipChildren(false);
@@ -222,5 +224,29 @@
                 }
             }
         }
+
+        @Override
+        public void setExpansion(float expansion, float proposedTranslation) {
+            if (expansion > 0f && expansion < 1f) {
+                return;
+            }
+            // The cases we must set select for marquee when QQS/QS collapsed, and QS full expanded.
+            // Expansion == 0f is when QQS is fully showing (as opposed to 1f, which is QS). At this
+            // point we want them to be selected so the tiles will marquee (but not at other points
+            // of expansion.
+            boolean selected = (expansion == 1f || proposedTranslation < 0f);
+            if (mLastSelected == selected) {
+                return;
+            }
+            // We set it as not important while we change this, so setting each tile as selected
+            // will not cause them to announce themselves until the user has actually selected the
+            // item.
+            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+            for (int i = 0; i < getChildCount(); i++) {
+                getChildAt(i).setSelected(selected);
+            }
+            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+            mLastSelected = selected;
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index 70685a6..222539d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -195,9 +195,6 @@
             // sibling methods to have special behavior for labelContainer.
             labelContainer.forceUnspecifiedMeasure = true
             secondaryLabel.alpha = 0f
-            // Do not marque in QQS
-            label.ellipsize = TextUtils.TruncateAt.END
-            secondaryLabel.ellipsize = TextUtils.TruncateAt.END
         }
         setLabelColor(getLabelColorForState(QSTile.State.DEFAULT_STATE))
         setSecondaryLabelColor(getSecondaryLabelColorForState(QSTile.State.DEFAULT_STATE))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 3890c1a..503b5c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -825,7 +825,11 @@
         if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
             // if udfps available, there will always be a tappable affordance to unlock
             // For example, the lock icon
-            showTransientIndication(R.string.keyguard_unlock_press);
+            if (mKeyguardBypassController.getUserHasDeviceEntryIntent()) {
+                showTransientIndication(R.string.keyguard_unlock_press);
+            } else {
+                showTransientIndication(R.string.keyguard_face_failed_use_fp);
+            }
         } else {
             showTransientIndication(R.string.keyguard_try_fingerprint);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 1b4ae9e..2c810c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -157,15 +157,13 @@
         // After the shelf has updated its yTranslation, explicitly set alpha=0 for view below shelf
         // to skip rendering them in the hardware layer. We do not set them invisible because that
         // runs invalidate & onDraw when these views return onscreen, which is more expensive.
+        if (shelf.getViewState().hidden) {
+            // When the shelf is hidden, it won't clip views, so we don't hide rows
+            return;
+        }
         final float shelfTop = shelf.getViewState().yTranslation;
 
         for (ExpandableView view : algorithmState.visibleChildren) {
-            if (view instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) view;
-                if (row.isHeadsUp() || row.isHeadsUpAnimatingAway()) {
-                    continue;
-                }
-            }
             final float viewTop = view.getViewState().yTranslation;
             if (viewTop >= shelfTop) {
                 view.getViewState().alpha = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 6802472..5a6db21 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -231,7 +231,9 @@
      * possible if AOD isn't even enabled or if the flag is disabled.
      */
     public boolean canControlUnlockedScreenOff() {
-        return getAlwaysOn() && mFeatureFlags.useNewLockscreenAnimations();
+        return getAlwaysOn()
+                && mFeatureFlags.useNewLockscreenAnimations()
+                && !getDisplayNeedsBlanking();
     }
 
     private boolean getBoolean(String propName, int resId) {
diff --git a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
index b38fc77..90e022a5 100644
--- a/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
+++ b/packages/SystemUI/src/com/android/systemui/util/sensors/ProximitySensor.java
@@ -290,15 +290,18 @@
             return;
         }
 
-        if (!mSecondaryThresholdSensor.isLoaded()) {
+
+        if (!mSecondaryThresholdSensor.isLoaded()) {  // No secondary
             logDebug("Primary sensor event: " + event.getBelow() + ". No secondary.");
             onSensorEvent(event);
-        } else if (event.getBelow()) {
+        } else if (event.getBelow()) {  // Covered? Check secondary.
             logDebug("Primary sensor event: " + event.getBelow() + ". Checking secondary.");
             if (mCancelSecondaryRunnable != null) {
                 mCancelSecondaryRunnable.run();
             }
             mSecondaryThresholdSensor.resume();
+        } else {  // Uncovered. Report immediately.
+            onSensorEvent(event);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 3320852..60b92ef 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -2248,6 +2248,11 @@
 
         @Override
         public void onClick(View view) {
+            // If the ringer drawer isn't open, don't let anything in it be clicked.
+            if (!mIsRingerDrawerOpen) {
+                return;
+            }
+
             setRingerMode(mClickedRingerMode);
 
             mRingerDrawerIconAnimatingSelected = getDrawerIconViewForMode(mClickedRingerMode);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
index cc2afe2..a34c598 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/sensors/ProximitySensorDualTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -60,6 +61,68 @@
     }
 
     @Test
+    public void testInitiallyAbovePrimary() {
+
+        TestableListener listener = new TestableListener();
+
+        mProximitySensor.register(listener);
+        assertTrue(mProximitySensor.isRegistered());
+        assertFalse(mThresholdSensorPrimary.isPaused());
+        assertTrue(mThresholdSensorSecondary.isPaused());
+        assertNull(listener.mLastEvent);
+        assertEquals(0, listener.mCallCount);
+
+        mThresholdSensorPrimary.triggerEvent(false, 0);
+        assertNotNull(listener.mLastEvent);
+        assertFalse(listener.mLastEvent.getBelow());
+        assertEquals(1, listener.mCallCount);
+    }
+
+    @Test
+    public void testInitiallyBelowPrimaryAboveSecondary() {
+
+        TestableListener listener = new TestableListener();
+
+        mProximitySensor.register(listener);
+        assertTrue(mProximitySensor.isRegistered());
+        assertFalse(mThresholdSensorPrimary.isPaused());
+        assertTrue(mThresholdSensorSecondary.isPaused());
+        assertNull(listener.mLastEvent);
+        assertEquals(0, listener.mCallCount);
+
+        mThresholdSensorPrimary.triggerEvent(true, 0);
+        assertNull(listener.mLastEvent);
+        assertEquals(0, listener.mCallCount);
+
+        mThresholdSensorSecondary.triggerEvent(false, 1);
+        assertNotNull(listener.mLastEvent);
+        assertFalse(listener.mLastEvent.getBelow());
+        assertEquals(1, listener.mCallCount);
+    }
+
+    @Test
+    public void testInitiallyBelowPrimaryAndSecondary() {
+
+        TestableListener listener = new TestableListener();
+
+        mProximitySensor.register(listener);
+        assertTrue(mProximitySensor.isRegistered());
+        assertFalse(mThresholdSensorPrimary.isPaused());
+        assertTrue(mThresholdSensorSecondary.isPaused());
+        assertNull(listener.mLastEvent);
+        assertEquals(0, listener.mCallCount);
+
+        mThresholdSensorPrimary.triggerEvent(true, 0);
+        assertNull(listener.mLastEvent);
+        assertEquals(0, listener.mCallCount);
+
+        mThresholdSensorSecondary.triggerEvent(true, 1);
+        assertNotNull(listener.mLastEvent);
+        assertTrue(listener.mLastEvent.getBelow());
+        assertEquals(1, listener.mCallCount);
+    }
+
+    @Test
     public void testPrimaryBelowDoesNotInvokeSecondary() {
         TestableListener listener = new TestableListener();
 
@@ -74,8 +137,6 @@
         mThresholdSensorPrimary.triggerEvent(false, 0);
         assertFalse(mThresholdSensorPrimary.isPaused());
         assertTrue(mThresholdSensorSecondary.isPaused());
-        assertNull(listener.mLastEvent);
-        assertEquals(0, listener.mCallCount);
     }
 
     @Test
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index a56b1db..5aec6aa 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -3285,57 +3285,6 @@
         }
     }
 
-    private void applyResourceOverlaysToWidgetsLocked(Set<String> packageNames, int userId,
-            boolean updateFrameworkRes) {
-        for (int i = 0, N = mProviders.size(); i < N; i++) {
-            Provider provider = mProviders.get(i);
-            if (provider.getUserId() != userId) {
-                continue;
-            }
-
-            final String packageName = provider.id.componentName.getPackageName();
-            if (!updateFrameworkRes && !packageNames.contains(packageName)) {
-                continue;
-            }
-
-            ApplicationInfo newAppInfo = null;
-            try {
-                newAppInfo = mPackageManager.getApplicationInfo(packageName,
-                        PackageManager.GET_SHARED_LIBRARY_FILES, userId);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "Failed to retrieve app info for " + packageName
-                        + " userId=" + userId, e);
-            }
-            if (newAppInfo == null) {
-                continue;
-            }
-            ApplicationInfo oldAppInfo = provider.info.providerInfo.applicationInfo;
-            if (!newAppInfo.sourceDir.equals(oldAppInfo.sourceDir)) {
-                // Overlay paths are generated against a particular version of an application.
-                // The overlays paths of a newly upgraded application are incompatible with the
-                // old version of the application.
-                continue;
-            }
-
-            // Isolate the changes relating to RROs. The app info must be copied to prevent
-            // affecting other parts of system server that may have cached this app info.
-            oldAppInfo = new ApplicationInfo(oldAppInfo);
-            oldAppInfo.overlayPaths = newAppInfo.overlayPaths.clone();
-            oldAppInfo.resourceDirs = newAppInfo.resourceDirs.clone();
-            provider.info.providerInfo.applicationInfo = oldAppInfo;
-
-            for (int j = 0, M = provider.widgets.size(); j < M; j++) {
-                Widget widget = provider.widgets.get(j);
-                if (widget.views != null) {
-                    widget.views.updateAppInfo(oldAppInfo);
-                }
-                if (widget.maskedViews != null) {
-                    widget.maskedViews.updateAppInfo(oldAppInfo);
-                }
-            }
-        }
-    }
-
     /**
      * Updates all providers with the specified package names, and records any providers that were
      * pruned.
@@ -4926,14 +4875,5 @@
         public void unlockUser(int userId) {
             handleUserUnlocked(userId);
         }
-
-        @Override
-        public void applyResourceOverlaysToWidgets(Set<String> packageNames, int userId,
-                boolean updateFrameworkRes) {
-            synchronized (mLock) {
-                applyResourceOverlaysToWidgetsLocked(new HashSet<>(packageNames), userId,
-                        updateFrameworkRes);
-            }
-        }
     }
 }
diff --git a/services/core/java/com/android/server/SensorPrivacyService.java b/services/core/java/com/android/server/SensorPrivacyService.java
index ecd620e..40e63da 100644
--- a/services/core/java/com/android/server/SensorPrivacyService.java
+++ b/services/core/java/com/android/server/SensorPrivacyService.java
@@ -21,7 +21,6 @@
 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
 import static android.app.ActivityManager.RunningServiceInfo;
 import static android.app.ActivityManager.RunningTaskInfo;
-import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_IGNORED;
 import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
@@ -382,17 +381,9 @@
 
             int sensor;
             if (result == MODE_IGNORED) {
-                if (code == OP_RECORD_AUDIO) {
+                if (code == OP_RECORD_AUDIO || code == OP_PHONE_CALL_MICROPHONE) {
                     sensor = MICROPHONE;
-                } else if (code == OP_CAMERA) {
-                    sensor = CAMERA;
-                } else {
-                    return;
-                }
-            } else if (result == MODE_ALLOWED) {
-                if (code == OP_PHONE_CALL_MICROPHONE) {
-                    sensor = MICROPHONE;
-                } else if (code == OP_PHONE_CALL_CAMERA) {
+                } else if (code == OP_CAMERA || code == OP_PHONE_CALL_CAMERA) {
                     sensor = CAMERA;
                 } else {
                     return;
@@ -1276,10 +1267,14 @@
                 case MICROPHONE:
                     mAppOpsManagerInternal.setGlobalRestriction(OP_RECORD_AUDIO, enabled,
                             mAppOpsRestrictionToken);
+                    mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_MICROPHONE, enabled,
+                            mAppOpsRestrictionToken);
                     break;
                 case CAMERA:
                     mAppOpsManagerInternal.setGlobalRestriction(OP_CAMERA, enabled,
                             mAppOpsRestrictionToken);
+                    mAppOpsManagerInternal.setGlobalRestriction(OP_PHONE_CALL_CAMERA, enabled,
+                            mAppOpsRestrictionToken);
                     break;
             }
         }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 07847f1..45e6f1ec 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -102,6 +102,7 @@
 import android.appwidget.AppWidgetManagerInternal;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
+import android.compat.annotation.Overridable;
 import android.content.ComponentName;
 import android.content.ComponentName.WithComponentName;
 import android.content.Context;
@@ -307,6 +308,7 @@
      */
     @ChangeId
     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
+    @Overridable
     static final long FGS_BG_START_RESTRICTION_CHANGE_ID = 170668199L;
 
     /**
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e0df4b7..99ae52c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -193,7 +193,6 @@
 import android.app.usage.UsageStatsManager;
 import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
-import android.appwidget.AppWidgetManagerInternal;
 import android.content.AttributionSource;
 import android.content.AutofillOptions;
 import android.content.BroadcastReceiver;
@@ -16598,13 +16597,6 @@
         if (updateFrameworkRes) {
             ParsingPackageUtils.readConfigUseRoundIcon(null);
         }
-
-        AppWidgetManagerInternal widgets = LocalServices.getService(AppWidgetManagerInternal.class);
-        if (widgets != null) {
-            widgets.applyResourceOverlaysToWidgets(new HashSet<>(packagesToUpdate), userId,
-                    updateFrameworkRes);
-        }
-
         mProcessList.updateApplicationInfoLOSP(packagesToUpdate, userId, updateFrameworkRes);
 
         if (updateFrameworkRes) {
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index a9905dc..64b9bd9 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -45,6 +45,9 @@
 import static android.app.AppOpsManager.OP_PLAY_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO;
 import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
+import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
+import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_RESUMED;
+import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED;
 import static android.app.AppOpsManager.OpEventProxyInfo;
 import static android.app.AppOpsManager.RestrictionBypass;
 import static android.app.AppOpsManager.SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
@@ -1238,6 +1241,11 @@
                     scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid, parent.packageName,
                             tag, true, event.getAttributionFlags(), event.getAttributionChainId());
                 }
+                // Note: this always sends MODE_ALLOWED, even if the mode is FOREGROUND
+                // TODO ntmyren: figure out how to get the real mode.
+                scheduleOpStartedIfNeededLocked(parent.op, parent.uid, parent.packageName,
+                        tag, event.getFlags(), MODE_ALLOWED, START_TYPE_RESUMED,
+                        event.getAttributionFlags(), event.getAttributionChainId());
             }
             mPausedInProgressEvents = null;
         }
@@ -3438,7 +3446,7 @@
                         + " package " + packageName + "flags: " +
                         AppOpsManager.flagsToString(flags));
                 return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
-                        packageName + " flags: " + AppOpsManager.flagsToString(flags));
+                        packageName);
             }
             final Op op = getOpLocked(ops, code, uid, true);
             final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
@@ -3945,13 +3953,15 @@
         }
 
         boolean isRestricted = false;
+        int startType = START_TYPE_FAILED;
         synchronized (this) {
             final Ops ops = getOpsLocked(uid, packageName, attributionTag,
                     pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
             if (ops == null) {
                 if (!dryRun) {
                     scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
-                            flags, AppOpsManager.MODE_IGNORED);
+                            flags, AppOpsManager.MODE_IGNORED, startType, attributionFlags,
+                            attributionChainId);
                 }
                 if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
                         + " package " + packageName + " flags: "
@@ -3977,7 +3987,7 @@
                     if (!dryRun) {
                         attributedOp.rejected(uidState.state, flags);
                         scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
-                                flags, uidMode);
+                                flags, uidMode, startType, attributionFlags, attributionChainId);
                     }
                     return new SyncNotedAppOp(uidMode, code, attributionTag, packageName);
                 }
@@ -3993,7 +4003,7 @@
                     if (!dryRun) {
                         attributedOp.rejected(uidState.state, flags);
                         scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
-                                flags, mode);
+                                flags, mode, startType, attributionFlags, attributionChainId);
                     }
                     return new SyncNotedAppOp(mode, code, attributionTag, packageName);
                 }
@@ -4011,12 +4021,14 @@
                         attributedOp.started(clientId, proxyUid, proxyPackageName,
                                 proxyAttributionTag, uidState.state, flags, attributionFlags,
                                 attributionChainId);
+                        startType = START_TYPE_STARTED;
                     }
                 } catch (RemoteException e) {
                     throw new RuntimeException(e);
                 }
                 scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, flags,
-                        isRestricted ? MODE_IGNORED : MODE_ALLOWED);
+                        isRestricted ? MODE_IGNORED : MODE_ALLOWED, startType, attributionFlags,
+                        attributionChainId);
             }
         }
 
@@ -4187,7 +4199,9 @@
     }
 
     private void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName,
-            String attributionTag, @OpFlags int flags, @Mode int result) {
+            String attributionTag, @OpFlags int flags, @Mode int result,
+            @AppOpsManager.OnOpStartedListener.StartedType int startedType,
+            @AttributionFlags int attributionFlags, int attributionChainId) {
         ArraySet<StartedCallback> dispatchedCallbacks = null;
         final int callbackListCount = mStartedWatchers.size();
         for (int i = 0; i < callbackListCount; i++) {
@@ -4213,12 +4227,13 @@
         mHandler.sendMessage(PooledLambda.obtainMessage(
                 AppOpsService::notifyOpStarted,
                 this, dispatchedCallbacks, code, uid, pkgName, attributionTag, flags,
-                result));
+                result, startedType, attributionFlags, attributionChainId));
     }
 
     private void notifyOpStarted(ArraySet<StartedCallback> callbacks,
             int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
-            @Mode int result) {
+            @Mode int result, @AppOpsManager.OnOpStartedListener.StartedType int startedType,
+            @AttributionFlags int attributionFlags, int attributionChainId) {
         final long identity = Binder.clearCallingIdentity();
         try {
             final int callbackCount = callbacks.size();
@@ -4226,7 +4241,7 @@
                 final StartedCallback callback = callbacks.valueAt(i);
                 try {
                     callback.mCallback.opStarted(code, uid, packageName, attributionTag, flags,
-                            result);
+                            result, startedType, attributionFlags, attributionChainId);
                 } catch (RemoteException e) {
                     /* do nothing */
                 }
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index f7d0914..34e2578 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -736,6 +736,11 @@
     private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
     private long mLoweredFromNormalToVibrateTime;
 
+    // Uid of the active hotword detection service to check if caller is the one or not.
+    @GuardedBy("mHotwordDetectionServiceUidLock")
+    private int mHotwordDetectionServiceUid = android.os.Process.INVALID_UID;
+    private final Object mHotwordDetectionServiceUidLock = new Object();
+
     // Array of Uids of valid accessibility services to check if caller is one of them
     private final Object mAccessibilityServiceUidsLock = new Object();
     @GuardedBy("mAccessibilityServiceUidsLock")
@@ -1337,6 +1342,9 @@
             updateAssistantUId(true);
             AudioSystem.setRttEnabled(mRttEnabled);
         }
+        synchronized (mHotwordDetectionServiceUidLock) {
+            AudioSystem.setHotwordDetectionServiceUid(mHotwordDetectionServiceUid);
+        }
         synchronized (mAccessibilityServiceUidsLock) {
             AudioSystem.setA11yServicesUids(mAccessibilityServiceUids);
         }
@@ -9108,6 +9116,16 @@
         }
 
         @Override
+        public void setHotwordDetectionServiceUid(int uid) {
+            synchronized (mHotwordDetectionServiceUidLock) {
+                if (mHotwordDetectionServiceUid != uid) {
+                    mHotwordDetectionServiceUid = uid;
+                    AudioSystem.setHotwordDetectionServiceUid(mHotwordDetectionServiceUid);
+                }
+            }
+        }
+
+        @Override
         public void setAccessibilityServiceUids(IntArray uids) {
             synchronized (mAccessibilityServiceUidsLock) {
                 if (uids.size() == 0) {
diff --git a/services/core/java/com/android/server/audio/AudioSystemAdapter.java b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
index 973fbd2..6d56780 100644
--- a/services/core/java/com/android/server/audio/AudioSystemAdapter.java
+++ b/services/core/java/com/android/server/audio/AudioSystemAdapter.java
@@ -367,6 +367,14 @@
     }
 
     /**
+     * Same as {@link AudioSystem#setHotwordDetectionServiceUid(int)}
+     * Communicate UID of current HotwordDetectionService to audio policy service.
+     */
+    public int setHotwordDetectionServiceUid(int uid) {
+        return AudioSystem.setHotwordDetectionServiceUid(uid);
+    }
+
+    /**
      * Same as {@link AudioSystem#setCurrentImeUid(int)}
      * Communicate UID of current InputMethodService to audio policy service.
      */
diff --git a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index f4327e8..6f38ed0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -82,7 +82,7 @@
 
     private long mStartTimeMs;
 
-    protected boolean mAuthAttempted;
+    private boolean mAuthAttempted;
 
     // TODO: This is currently hard to maintain, as each AuthenticationClient subclass must update
     //  the state. We should think of a way to improve this in the future.
@@ -98,6 +98,12 @@
      */
     protected abstract void handleLifecycleAfterAuth(boolean authenticated);
 
+    /**
+     * @return true if a user was detected (i.e. face was found, fingerprint sensor was touched.
+     *         etc)
+     */
+    public abstract boolean wasUserDetected();
+
     public AuthenticationClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
             @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
             int targetUserId, long operationId, boolean restricted, @NonNull String owner,
@@ -180,7 +186,8 @@
                 + ", isBP: " + isBiometricPrompt()
                 + ", listener: " + listener
                 + ", requireConfirmation: " + mRequireConfirmation
-                + ", user: " + getTargetUserId());
+                + ", user: " + getTargetUserId()
+                + ", clientMonitor: " + toString());
 
         final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId());
         if (isCryptoOperation()) {
@@ -304,6 +311,11 @@
                 public void handleLifecycleAfterAuth() {
                     AuthenticationClient.this.handleLifecycleAfterAuth(true /* authenticated */);
                 }
+
+                @Override
+                public void sendAuthenticationCanceled() {
+                    sendCancelOnly(listener);
+                }
             });
         } else {
             // Allow system-defined limit of number of attempts before giving up
@@ -338,10 +350,30 @@
                 public void handleLifecycleAfterAuth() {
                     AuthenticationClient.this.handleLifecycleAfterAuth(false /* authenticated */);
                 }
+
+                @Override
+                public void sendAuthenticationCanceled() {
+                    sendCancelOnly(listener);
+                }
             });
         }
     }
 
+    private void sendCancelOnly(@Nullable ClientMonitorCallbackConverter listener) {
+        if (listener == null) {
+            Slog.e(TAG, "Unable to sendAuthenticationCanceled, listener null");
+            return;
+        }
+        try {
+            listener.onError(getSensorId(),
+                    getCookie(),
+                    BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+                    0 /* vendorCode */);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Remote exception", e);
+        }
+    }
+
     @Override
     public void onAcquired(int acquiredInfo, int vendorCode) {
         super.onAcquired(acquiredInfo, vendorCode);
@@ -355,9 +387,11 @@
     }
 
     @Override
-    public void onError(int errorCode, int vendorCode) {
+    public void onError(@BiometricConstants.Errors int errorCode, int vendorCode) {
         super.onError(errorCode, vendorCode);
         mState = STATE_STOPPED;
+
+        CoexCoordinator.getInstance().onAuthenticationError(this, errorCode, this::vibrateError);
     }
 
     /**
@@ -419,4 +453,8 @@
     public boolean interruptsPrecedingClients() {
         return true;
     }
+
+    public boolean wasAuthAttempted() {
+        return mAuthAttempted;
+    }
 }
diff --git a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
index a15ecad..25d4a38 100644
--- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
@@ -22,6 +22,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.hardware.biometrics.BiometricConstants;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.Slog;
@@ -54,7 +55,7 @@
 
     /**
      * Callback interface notifying the owner of "results" from the CoexCoordinator's business
-     * logic.
+     * logic for accept and reject.
      */
     interface Callback {
         /**
@@ -73,6 +74,22 @@
          * from scheduler if auth was successful).
          */
         void handleLifecycleAfterAuth();
+
+        /**
+         * Requests the owner to notify the caller that authentication was canceled.
+         */
+        void sendAuthenticationCanceled();
+    }
+
+    /**
+     * Callback interface notifying the owner of "results" from the CoexCoordinator's business
+     * logic for errors.
+     */
+    interface ErrorCallback {
+        /**
+         * Requests the owner to initiate a vibration for this event.
+         */
+        void sendHapticFeedback();
     }
 
     private static CoexCoordinator sInstance;
@@ -198,6 +215,9 @@
         mClientMap.remove(sensorType);
     }
 
+    /**
+     * Notify the coordinator that authentication succeeded (accepted)
+     */
     public void onAuthenticationSucceeded(long currentTimeMillis,
             @NonNull AuthenticationClient<?> client,
             @NonNull Callback callback) {
@@ -268,6 +288,9 @@
         }
     }
 
+    /**
+     * Notify the coordinator that a rejection has occurred.
+     */
     public void onAuthenticationRejected(long currentTimeMillis,
             @NonNull AuthenticationClient<?> client,
             @LockoutTracker.LockoutMode int lockoutMode,
@@ -352,11 +375,63 @@
         }
     }
 
+    /**
+     * Notify the coordinator that an error has occurred.
+     */
+    public void onAuthenticationError(@NonNull AuthenticationClient<?> client,
+            @BiometricConstants.Errors int error, @NonNull ErrorCallback callback) {
+        // Figure out non-coex state
+        final boolean shouldUsuallyVibrate;
+        if (isCurrentFaceAuth(client)) {
+            final boolean notDetectedOnKeyguard = client.isKeyguard() && !client.wasUserDetected();
+            final boolean authAttempted = client.wasAuthAttempted();
+
+            switch (error) {
+                case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
+                case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
+                case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
+                    shouldUsuallyVibrate = authAttempted && !notDetectedOnKeyguard;
+                    break;
+                default:
+                    shouldUsuallyVibrate = false;
+                    break;
+            }
+        } else {
+            shouldUsuallyVibrate = false;
+        }
+
+        // Figure out coex state
+        final boolean keyguardAdvancedLogic = mAdvancedLogicEnabled && client.isKeyguard();
+        final boolean hapticSuppressedByCoex;
+
+        if (keyguardAdvancedLogic) {
+            if (isSingleAuthOnly(client)) {
+                hapticSuppressedByCoex = false;
+            } else {
+                hapticSuppressedByCoex = isCurrentFaceAuth(client)
+                        && !client.isKeyguardBypassEnabled();
+            }
+        } else {
+            hapticSuppressedByCoex = false;
+        }
+
+        // Combine and send feedback if appropriate
+        Slog.d(TAG, "shouldUsuallyVibrate: " + shouldUsuallyVibrate
+                + ", hapticSuppressedByCoex: " + hapticSuppressedByCoex);
+        if (shouldUsuallyVibrate && !hapticSuppressedByCoex) {
+            callback.sendHapticFeedback();
+        }
+    }
+
     @Nullable
     private SuccessfulAuth popSuccessfulFaceAuthIfExists(long currentTimeMillis) {
         for (SuccessfulAuth auth : mSuccessfulAuths) {
             if (currentTimeMillis - auth.mAuthTimestamp >= SUCCESSFUL_AUTH_VALID_DURATION_MS) {
-                Slog.d(TAG, "Removing stale auth: " + auth);
+                // TODO(b/193089985): This removes the auth but does not notify the client with
+                //  an appropriate lifecycle event (such as ERROR_CANCELED), and violates the
+                //  API contract. However, this might be OK for now since the validity duration
+                //  is way longer than the time it takes to auth with fingerprint.
+                Slog.e(TAG, "Removing stale auth: " + auth);
                 mSuccessfulAuths.remove(auth);
             } else if (auth.mSensorType == SENSOR_TYPE_FACE) {
                 mSuccessfulAuths.remove(auth);
@@ -367,9 +442,13 @@
     }
 
     private void removeAndFinishAllFaceFromQueue() {
+        // Note that these auth are all successful, but have never notified the client (e.g.
+        // keyguard). To comply with the authentication lifecycle, we must notify the client that
+        // auth is "done". The safest thing to do is to send ERROR_CANCELED.
         for (SuccessfulAuth auth : mSuccessfulAuths) {
             if (auth.mSensorType == SENSOR_TYPE_FACE) {
-                Slog.d(TAG, "Removing from queue and finishing: " + auth);
+                Slog.d(TAG, "Removing from queue, canceling, and finishing: " + auth);
+                auth.mCallback.sendAuthenticationCanceled();
                 auth.mCallback.handleLifecycleAfterAuth();
                 mSuccessfulAuths.remove(auth);
             }
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index f7fd8d0..d66a279 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -127,7 +127,8 @@
         }
     }
 
-    private boolean wasUserDetected() {
+    @Override
+    public boolean wasUserDetected() {
         // Do not provide haptic feedback if the user was not detected, and an error (usually
         // ERROR_TIMEOUT) is received.
         return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED
@@ -160,7 +161,7 @@
     }
 
     @Override
-    public void onError(int error, int vendorCode) {
+    public void onError(@BiometricConstants.Errors int error, int vendorCode) {
         mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
                 getStartTimeMs(),
                 System.currentTimeMillis() - getStartTimeMs() /* latency */,
@@ -169,25 +170,8 @@
                 vendorCode,
                 getTargetUserId()));
 
-        switch (error) {
-            case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
-                if (!wasUserDetected() && !isBiometricPrompt()) {
-                    // No vibration if user was not detected on keyguard
-                    break;
-                }
-            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
-            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
-                if (mAuthAttempted) {
-                    // Only vibrate if auth was attempted. If the user was already locked out prior
-                    // to starting authentication, do not vibrate.
-                    vibrateError();
-                }
-                break;
-            case BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL:
-                BiometricNotificationUtils.showReEnrollmentNotification(getContext());
-                break;
-            default:
-                break;
+        if (error == BiometricConstants.BIOMETRIC_ERROR_RE_ENROLL) {
+            BiometricNotificationUtils.showReEnrollmentNotification(getContext());
         }
 
         super.onError(error, vendorCode);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index c33b957..33950af 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -115,7 +115,8 @@
         }
     }
 
-    private boolean wasUserDetected() {
+    @Override
+    public boolean wasUserDetected() {
         // Do not provide haptic feedback if the user was not detected, and an error (usually
         // ERROR_TIMEOUT) is received.
         return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED
@@ -147,7 +148,7 @@
     }
 
     @Override
-    public void onError(int error, int vendorCode) {
+    public void onError(@BiometricConstants.Errors int error, int vendorCode) {
         mUsageStats.addEvent(new UsageStats.AuthenticationEvent(
                 getStartTimeMs(),
                 System.currentTimeMillis() - getStartTimeMs() /* latency */,
@@ -156,24 +157,6 @@
                 vendorCode,
                 getTargetUserId()));
 
-        switch (error) {
-            case BiometricConstants.BIOMETRIC_ERROR_TIMEOUT:
-                if (!wasUserDetected() && !isBiometricPrompt()) {
-                    // No vibration if user was not detected on keyguard
-                    break;
-                }
-            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT:
-            case BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT:
-                if (mAuthAttempted) {
-                    // Only vibrate if auth was attempted. If the user was already locked out prior
-                    // to starting authentication, do not vibrate.
-                    vibrateError();
-                }
-                break;
-            default:
-                break;
-        }
-
         super.onError(error, vendorCode);
     }
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 8835c1e0..37ee76a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -106,6 +106,12 @@
     }
 
     @Override
+    public boolean wasUserDetected() {
+        // TODO: Update if it needs to be used for fingerprint, i.e. success/reject, error_timeout
+        return false;
+    }
+
+    @Override
     public void onAuthenticated(BiometricAuthenticator.Identifier identifier,
             boolean authenticated, ArrayList<Byte> token) {
         super.onAuthenticated(identifier, authenticated, token);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 83f1480..5060744 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -153,6 +153,12 @@
     }
 
     @Override
+    public boolean wasUserDetected() {
+        // TODO: Update if it needs to be used for fingerprint, i.e. success/reject, error_timeout
+        return false;
+    }
+
+    @Override
     public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) {
         mLockoutFrameworkImpl.addFailedAttemptForUser(userId);
         return super.handleFailedAttempt(userId);
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index f23ae6e..186986e 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -153,7 +153,7 @@
                 updateVoteLocked(displayId, priority, vote);
             }
         };
-        mSensorObserver = new SensorObserver(context, ballotBox);
+        mSensorObserver = new SensorObserver(context, ballotBox, injector);
         mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
         mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
         mDeviceConfig = injector.getDeviceConfig();
@@ -2127,27 +2127,34 @@
         }
     }
 
-    private static class SensorObserver implements ProximityActiveListener {
-        private static final String PROXIMITY_SENSOR_NAME = null;
-        private static final String PROXIMITY_SENSOR_TYPE = Sensor.STRING_TYPE_PROXIMITY;
+    private final class SensorObserver implements ProximityActiveListener,
+            DisplayManager.DisplayListener {
+        private final String mProximitySensorName = null;
+        private final String mProximitySensorType = Sensor.STRING_TYPE_PROXIMITY;
 
         private final BallotBox mBallotBox;
         private final Context mContext;
+        private final Injector mInjector;
 
         private DisplayManager mDisplayManager;
         private DisplayManagerInternal mDisplayManagerInternal;
         private boolean mIsProxActive = false;
+        private final SparseBooleanArray mDozeStateByDisplay;
 
-        SensorObserver(Context context, BallotBox ballotBox) {
+        SensorObserver(Context context, BallotBox ballotBox, Injector injector) {
             mContext = context;
             mBallotBox = ballotBox;
+            mInjector = injector;
+            mDozeStateByDisplay = new SparseBooleanArray();
         }
 
         @Override
         public void onProximityActive(boolean isActive) {
-            if (mIsProxActive != isActive) {
-                mIsProxActive = isActive;
-                recalculateVotes();
+            synchronized (mLock) {
+                if (mIsProxActive != isActive) {
+                    mIsProxActive = isActive;
+                    recalculateVotesLocked();
+                }
             }
         }
 
@@ -2158,17 +2165,27 @@
             final SensorManagerInternal sensorManager =
                     LocalServices.getService(SensorManagerInternal.class);
             sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this);
+
+            synchronized (mLock) {
+                for (Display d : mDisplayManager.getDisplays()) {
+                    mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d));
+                }
+            }
+            mInjector.registerDisplayListener(this, BackgroundThread.getHandler(),
+                    DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+                            | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+                            | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
         }
 
-        private void recalculateVotes() {
+        private void recalculateVotesLocked() {
             final Display[] displays = mDisplayManager.getDisplays();
             for (Display d : displays) {
                 int displayId = d.getDisplayId();
                 Vote vote = null;
-                if (mIsProxActive) {
+                if (mIsProxActive && !mDozeStateByDisplay.get(displayId)) {
                     final RefreshRateRange rate =
                             mDisplayManagerInternal.getRefreshRateForDisplayAndSensor(
-                                    displayId, PROXIMITY_SENSOR_NAME, PROXIMITY_SENSOR_TYPE);
+                                    displayId, mProximitySensorName, mProximitySensorType);
                     if (rate != null) {
                         vote = Vote.forRefreshRates(rate.min, rate.max);
                     }
@@ -2180,6 +2197,41 @@
         void dumpLocked(PrintWriter pw) {
             pw.println("  SensorObserver");
             pw.println("    mIsProxActive=" + mIsProxActive);
+            pw.println("    mDozeStateByDisplay:");
+            for (int i = 0; i < mDozeStateByDisplay.size(); i++) {
+                final int id = mDozeStateByDisplay.keyAt(i);
+                final boolean dozed = mDozeStateByDisplay.valueAt(i);
+                pw.println("      " + id + " -> " + dozed);
+            }
+        }
+
+        @Override
+        public void onDisplayAdded(int displayId) {
+            boolean isDozeState = mInjector.isDozeState(mDisplayManager.getDisplay(displayId));
+            synchronized (mLock) {
+                mDozeStateByDisplay.put(displayId, isDozeState);
+                recalculateVotesLocked();
+            }
+        }
+
+        @Override
+        public void onDisplayChanged(int displayId) {
+            boolean wasDozeState = mDozeStateByDisplay.get(displayId);
+            synchronized (mLock) {
+                mDozeStateByDisplay.put(displayId,
+                        mInjector.isDozeState(mDisplayManager.getDisplay(displayId)));
+                if (wasDozeState != mDozeStateByDisplay.get(displayId)) {
+                    recalculateVotesLocked();
+                }
+            }
+        }
+
+        @Override
+        public void onDisplayRemoved(int displayId) {
+            synchronized (mLock) {
+                mDozeStateByDisplay.delete(displayId);
+                recalculateVotesLocked();
+            }
         }
     }
 
@@ -2411,6 +2463,8 @@
                 Handler handler, long flags);
 
         BrightnessInfo getBrightnessInfo(int displayId);
+
+        boolean isDozeState(Display d);
     }
 
     @VisibleForTesting
@@ -2463,6 +2517,11 @@
             return null;
         }
 
+        @Override
+        public boolean isDozeState(Display d) {
+            return Display.isDozeState(d.getState());
+        }
+
         private DisplayManager getDisplayManager() {
             if (mDisplayManager == null) {
                 mDisplayManager = mContext.getSystemService(DisplayManager.class);
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 06ff691..ed9b539 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -1287,20 +1287,6 @@
                 }
             }
 
-            // This package isn't technically installed and won't be written to settings, so we can
-            // treat it as filtered until it's available again.
-            final AndroidPackage targetPkg = targetPkgSetting.pkg;
-            if (targetPkg == null) {
-                if (DEBUG_LOGGING) {
-                    Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
-                }
-                return true;
-            }
-            if (targetPkg.isStaticSharedLibrary()) {
-                // not an app, this filtering takes place at a higher level
-                return false;
-            }
-            final String targetName = targetPkg.getPackageName();
             if (DEBUG_TRACING) {
                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "getAppId");
             }
@@ -1343,6 +1329,21 @@
                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                 }
             }
+
+            // This package isn't technically installed and won't be written to settings, so we can
+            // treat it as filtered until it's available again.
+            final AndroidPackage targetPkg = targetPkgSetting.pkg;
+            if (targetPkg == null) {
+                if (DEBUG_LOGGING) {
+                    Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
+                }
+                return true;
+            }
+            if (targetPkg.isStaticSharedLibrary()) {
+                // not an app, this filtering takes place at a higher level
+                return false;
+            }
+
             try {
                 if (DEBUG_TRACING) {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mForceQueryable");
@@ -1415,6 +1416,7 @@
                 if (DEBUG_TRACING) {
                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper");
                 }
+                final String targetName = targetPkg.getPackageName();
                 if (callingSharedPkgSettings != null) {
                     int size = callingSharedPkgSettings.size();
                     for (int index = 0; index < size; index++) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ee44c10..904a1f0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -24838,11 +24838,11 @@
             pw.println("vers,1");
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_VERSION)
-                && packageName == null) {
-            // dump version information for all volumes with installed packages
-            dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
+        // reader
+        if (dumpState.isDumping(DumpState.DUMP_VERSION) && packageName == null) {
+            if (!checkin) {
+                dump(DumpState.DUMP_VERSION, fd, pw, dumpState);
+            }
         }
 
         if (!checkin
@@ -24873,8 +24873,7 @@
             ipw.decreaseIndent();
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_VERIFIERS)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_VERIFIERS) && packageName == null) {
             final String requiredVerifierPackage = mRequiredVerifierPackage;
             if (!checkin) {
                 if (dumpState.onTitlePrinted()) {
@@ -24895,8 +24894,7 @@
             }
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_DOMAIN_VERIFIER) && packageName == null) {
             final DomainVerificationProxy proxy = mDomainVerificationManager.getProxy();
             final ComponentName verifierComponent = proxy.getComponentName();
             if (verifierComponent != null) {
@@ -24923,13 +24921,11 @@
             }
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_LIBS)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_LIBS) && packageName == null) {
             dump(DumpState.DUMP_LIBS, fd, pw, dumpState);
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_FEATURES)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_FEATURES) && packageName == null) {
             if (dumpState.onTitlePrinted()) {
                 pw.println();
             }
@@ -24939,7 +24935,12 @@
 
             synchronized (mAvailableFeatures) {
                 for (FeatureInfo feat : mAvailableFeatures.values()) {
-                    if (!checkin) {
+                    if (checkin) {
+                        pw.print("feat,");
+                        pw.print(feat.name);
+                        pw.print(",");
+                        pw.println(feat.version);
+                    } else {
                         pw.print("  ");
                         pw.print(feat.name);
                         if (feat.version > 0) {
@@ -24947,73 +24948,55 @@
                             pw.print(feat.version);
                         }
                         pw.println();
-                    } else {
-                        pw.print("feat,");
-                        pw.print(feat.name);
-                        pw.print(",");
-                        pw.println(feat.version);
                     }
                 }
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_ACTIVITY_RESOLVERS)) {
             synchronized (mLock) {
                 mComponentResolver.dumpActivityResolvers(pw, dumpState, packageName);
             }
         }
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_RECEIVER_RESOLVERS)) {
             synchronized (mLock) {
                 mComponentResolver.dumpReceiverResolvers(pw, dumpState, packageName);
             }
         }
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_RESOLVERS)) {
             synchronized (mLock) {
                 mComponentResolver.dumpServiceResolvers(pw, dumpState, packageName);
             }
         }
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_CONTENT_RESOLVERS)) {
             synchronized (mLock) {
                 mComponentResolver.dumpProviderResolvers(pw, dumpState, packageName);
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_PREFERRED)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED)) {
             dump(DumpState.DUMP_PREFERRED, fd, pw, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_PREFERRED_XML)) {
             dump(DumpState.DUMP_PREFERRED_XML, fd, pw, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_DOMAIN_PREFERRED)) {
             dump(DumpState.DUMP_DOMAIN_PREFERRED, fd, pw, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_PERMISSIONS)) {
             mSettings.dumpPermissions(pw, packageName, permissionNames, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_PROVIDERS)) {
             synchronized (mLock) {
                 mComponentResolver.dumpContentProviders(pw, dumpState, packageName);
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
             synchronized (mLock) {
                 mSettings.getKeySetManagerService().dumpLPr(pw, packageName, dumpState);
             }
@@ -25028,15 +25011,11 @@
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_QUERIES)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_QUERIES)) {
             dump(DumpState.DUMP_QUERIES, fd, pw, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_SHARED_USERS)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) {
             // This cannot be moved to ComputerEngine since the set of packages in the
             // SharedUserSetting do not have a copy.
             synchronized (mLock) {
@@ -25044,9 +25023,7 @@
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_CHANGES)
-                && packageName == null) {
+        if (dumpState.isDumping(DumpState.DUMP_CHANGES)) {
             if (dumpState.onTitlePrinted()) pw.println();
             pw.println("Package Changes:");
             synchronized (mLock) {
@@ -25073,9 +25050,7 @@
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_FROZEN)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) {
             // XXX should handle packageName != null by dumping only install data that
             // the given package is involved with.
             if (dumpState.onTitlePrinted()) pw.println();
@@ -25096,9 +25071,7 @@
             ipw.decreaseIndent();
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_VOLUMES)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_VOLUMES) && packageName == null) {
             if (dumpState.onTitlePrinted()) pw.println();
 
             final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ", 120);
@@ -25117,61 +25090,50 @@
             ipw.decreaseIndent();
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_SERVICE_PERMISSIONS)
                 && packageName == null) {
             synchronized (mLock) {
                 mComponentResolver.dumpServicePermissions(pw, dumpState);
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_DEXOPT)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_DEXOPT)) {
             if (dumpState.onTitlePrinted()) pw.println();
             dump(DumpState.DUMP_DEXOPT, fd, pw, dumpState);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_COMPILER_STATS)) {
             if (dumpState.onTitlePrinted()) pw.println();
             dump(DumpState.DUMP_COMPILER_STATS, fd, pw, dumpState);
         }
 
-        if (dumpState.isDumping(DumpState.DUMP_MESSAGES)
-                && packageName == null) {
-            if (!checkin) {
-                if (dumpState.onTitlePrinted()) pw.println();
-                synchronized (mLock) {
-                    mSettings.dumpReadMessagesLPr(pw, dumpState);
-                }
-                pw.println();
-                pw.println("Package warning messages:");
-                dumpCriticalInfo(pw, null);
-            } else {
-                dumpCriticalInfo(pw, "msg,");
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
+            if (dumpState.onTitlePrinted()) pw.println();
+            synchronized (mLock) {
+                mSettings.dumpReadMessagesLPr(pw, dumpState);
             }
+            pw.println();
+            pw.println("Package warning messages:");
+            dumpCriticalInfo(pw, null);
+        }
+
+        if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) {
+            dumpCriticalInfo(pw, "msg,");
         }
 
         // PackageInstaller should be called outside of mPackages lock
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_INSTALLS)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_INSTALLS) && packageName == null) {
             // XXX should handle packageName != null by dumping only install data that
             // the given package is involved with.
             if (dumpState.onTitlePrinted()) pw.println();
             mInstallerService.dump(new IndentingPrintWriter(pw, "  ", 120));
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_APEX)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_APEX)) {
             mApexManager.dump(pw, packageName);
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_PER_UID_READ_TIMEOUTS)
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_PER_UID_READ_TIMEOUTS)
                 && packageName == null) {
             pw.println();
             pw.println("Per UID read timeouts:");
@@ -25190,9 +25152,7 @@
             }
         }
 
-        if (!checkin
-                && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)
-                && packageName == null) {
+        if (!checkin && dumpState.isDumping(DumpState.DUMP_SNAPSHOT_STATISTICS)) {
             pw.println("Snapshot statistics");
             if (!mSnapshotEnabled) {
                 pw.println("  Snapshots disabled");
@@ -26533,7 +26493,7 @@
     }
 
     boolean readPermissionStateForUser(@UserIdInt int userId) {
-        synchronized (mPackages) {
+        synchronized (mLock) {
             mPermissionManager.writeLegacyPermissionStateTEMP();
             mSettings.readPermissionStateForUserSyncLPr(userId);
             mPermissionManager.readLegacyPermissionStateTEMP();
@@ -26609,7 +26569,7 @@
         if (packageName == null || alias == null) {
             return null;
         }
-        synchronized(mLock) {
+        synchronized (mLock) {
             final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null
                     || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
@@ -26656,7 +26616,7 @@
         if (packageName == null || ks == null) {
             return false;
         }
-        synchronized(mLock) {
+        synchronized (mLock) {
             final AndroidPackage pkg = mPackages.get(packageName);
             if (pkg == null
                     || shouldFilterApplicationLocked(getPackageSetting(pkg.getPackageName()),
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index bf82bd8..88dd033 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -176,6 +176,10 @@
         name = orig.name;
         realName = orig.realName;
         doCopy(orig);
+        // Clone the user states.
+        for (int i = 0; i < mUserState.size(); i++) {
+            mUserState.put(mUserState.keyAt(i), new PackageUserState(mUserState.valueAt(i)));
+        }
     }
 
     public void setInstallerPackageName(String packageName) {
@@ -314,6 +318,7 @@
 
     void setInstalled(boolean inst, int userId) {
         modifyUserState(userId).installed = inst;
+        onChanged();
     }
 
     boolean getInstalled(int userId) {
@@ -326,6 +331,7 @@
 
     void setInstallReason(int installReason, int userId) {
         modifyUserState(userId).installReason = installReason;
+        onChanged();
     }
 
     int getUninstallReason(int userId) {
@@ -334,10 +340,13 @@
 
     void setUninstallReason(@UninstallReason int uninstallReason, int userId) {
         modifyUserState(userId).uninstallReason = uninstallReason;
+        onChanged();
     }
 
     boolean setOverlayPaths(OverlayPaths overlayPaths, int userId) {
-        return modifyUserState(userId).setOverlayPaths(overlayPaths);
+        boolean returnValue = modifyUserState(userId).setOverlayPaths(overlayPaths);
+        onChanged();
+        return returnValue;
     }
 
     OverlayPaths getOverlayPaths(int userId) {
@@ -346,7 +355,10 @@
 
     boolean setOverlayPathsForLibrary(String libName, OverlayPaths overlayPaths,
             int userId) {
-        return modifyUserState(userId).setSharedLibraryOverlayPaths(libName, overlayPaths);
+        boolean returnValue =  modifyUserState(userId)
+                .setSharedLibraryOverlayPaths(libName, overlayPaths);
+        onChanged();
+        return returnValue;
     }
 
     Map<String, OverlayPaths> getOverlayPathsForLibrary(int userId) {
@@ -395,6 +407,7 @@
 
     void setCeDataInode(long ceDataInode, int userId) {
         modifyUserState(userId).ceDataInode = ceDataInode;
+        onChanged();
     }
 
     boolean getStopped(int userId) {
@@ -403,6 +416,7 @@
 
     void setStopped(boolean stop, int userId) {
         modifyUserState(userId).stopped = stop;
+        onChanged();
     }
 
     boolean getNotLaunched(int userId) {
@@ -411,6 +425,7 @@
 
     void setNotLaunched(boolean stop, int userId) {
         modifyUserState(userId).notLaunched = stop;
+        onChanged();
     }
 
     boolean getHidden(int userId) {
@@ -419,6 +434,7 @@
 
     void setHidden(boolean hidden, int userId) {
         modifyUserState(userId).hidden = hidden;
+        onChanged();
     }
 
     int getDistractionFlags(int userId) {
@@ -427,6 +443,7 @@
 
     void setDistractionFlags(int distractionFlags, int userId) {
         modifyUserState(userId).distractionFlags = distractionFlags;
+        onChanged();
     }
 
     boolean getSuspended(int userId) {
@@ -487,6 +504,7 @@
 
     void setInstantApp(boolean instantApp, int userId) {
         modifyUserState(userId).instantApp = instantApp;
+        onChanged();
     }
 
     boolean getVirtulalPreload(int userId) {
@@ -495,6 +513,7 @@
 
     void setVirtualPreload(boolean virtualPreload, int userId) {
         modifyUserState(userId).virtualPreload = virtualPreload;
+        onChanged();
     }
 
     void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
@@ -547,20 +566,24 @@
 
     void setEnabledComponents(ArraySet<String> components, int userId) {
         modifyUserState(userId).enabledComponents = components;
+        onChanged();
     }
 
     void setDisabledComponents(ArraySet<String> components, int userId) {
         modifyUserState(userId).disabledComponents = components;
+        onChanged();
     }
 
     void setEnabledComponentsCopy(ArraySet<String> components, int userId) {
         modifyUserState(userId).enabledComponents = components != null
                 ? new ArraySet<String>(components) : null;
+        onChanged();
     }
 
     void setDisabledComponentsCopy(ArraySet<String> components, int userId) {
         modifyUserState(userId).disabledComponents = components != null
                 ? new ArraySet<String>(components) : null;
+        onChanged();
     }
 
     PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) {
@@ -582,10 +605,12 @@
 
     void addDisabledComponent(String componentClassName, int userId) {
         modifyUserStateComponents(userId, true, false).disabledComponents.add(componentClassName);
+        onChanged();
     }
 
     void addEnabledComponent(String componentClassName, int userId) {
         modifyUserStateComponents(userId, false, true).enabledComponents.add(componentClassName);
+        onChanged();
     }
 
     boolean enableComponentLPw(String componentClassName, int userId) {
@@ -593,6 +618,9 @@
         boolean changed = state.disabledComponents != null
                 ? state.disabledComponents.remove(componentClassName) : false;
         changed |= state.enabledComponents.add(componentClassName);
+        if (changed) {
+            onChanged();
+        }
         return changed;
     }
 
@@ -601,6 +629,9 @@
         boolean changed = state.enabledComponents != null
                 ? state.enabledComponents.remove(componentClassName) : false;
         changed |= state.disabledComponents.add(componentClassName);
+        if (changed) {
+            onChanged();
+        }
         return changed;
     }
 
@@ -610,6 +641,9 @@
                 ? state.disabledComponents.remove(componentClassName) : false;
         changed |= state.enabledComponents != null
                 ? state.enabledComponents.remove(componentClassName) : false;
+        if (changed) {
+            onChanged();
+        }
         return changed;
     }
 
@@ -701,6 +735,7 @@
     PackageSettingBase setPath(@NonNull File path) {
         this.mPath = path;
         this.mPathString = path.toString();
+        onChanged();
         return this;
     }
 
@@ -722,7 +757,9 @@
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
     public boolean overrideNonLocalizedLabelAndIcon(@NonNull ComponentName component,
             @Nullable String label, @Nullable Integer icon, @UserIdInt int userId) {
-        return modifyUserState(userId).overrideLabelAndIcon(component, label, icon);
+        boolean returnValue = modifyUserState(userId).overrideLabelAndIcon(component, label, icon);
+        onChanged();
+        return returnValue;
     }
 
     /**
@@ -732,6 +769,7 @@
      */
     public void resetOverrideComponentLabelIcon(@UserIdInt int userId) {
         modifyUserState(userId).resetOverrideComponentLabelIcon();
+        onChanged();
     }
 
     /**
@@ -741,6 +779,7 @@
      */
     public void setSplashScreenTheme(@UserIdInt int userId, @Nullable String themeName) {
         modifyUserState(userId).splashScreenTheme = themeName;
+        onChanged();
     }
 
     /**
@@ -776,6 +815,7 @@
      */
     public void setStatesOnCommit() {
         incrementalStates.onCommit(IncrementalManager.isIncrementalPath(getPathString()));
+        onChanged();
     }
 
     /**
@@ -783,6 +823,7 @@
      */
     public void setIncrementalStatesCallback(IncrementalStates.Callback callback) {
         incrementalStates.setCallback(callback);
+        onChanged();
     }
 
     /**
@@ -791,6 +832,7 @@
      */
     public void setLoadingProgress(float progress) {
         incrementalStates.setProgress(progress);
+        onChanged();
     }
 
     public long getFirstInstallTime() {
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index e85fa23..0f4f58b 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -228,17 +228,20 @@
 
             Vibration.Status status = null;
             while (!mStepQueue.isEmpty()) {
-                long waitTime = mStepQueue.calculateWaitTime();
-                if (waitTime <= 0) {
-                    mStepQueue.consumeNext();
-                } else {
-                    synchronized (mLock) {
+                long waitTime;
+                synchronized (mLock) {
+                    waitTime = mStepQueue.calculateWaitTime();
+                    if (waitTime > 0) {
                         try {
                             mLock.wait(waitTime);
                         } catch (InterruptedException e) {
                         }
                     }
                 }
+                // If we waited, the queue may have changed, so let the loop run again.
+                if (waitTime <= 0) {
+                    mStepQueue.consumeNext();
+                }
                 Vibration.Status currentStatus = mStop ? Vibration.Status.CANCELLED
                         : mStepQueue.calculateVibrationStatus(sequentialEffectSize);
                 if (status == null && currentStatus != Vibration.Status.RUNNING) {
@@ -387,15 +390,13 @@
         }
 
         /** Returns the time in millis to wait before calling {@link #consumeNext()}. */
+        @GuardedBy("mLock")
         public long calculateWaitTime() {
-            Step nextStep;
-            synchronized (mLock) {
-                if (!mPendingOnVibratorCompleteSteps.isEmpty()) {
-                    // Steps anticipated by vibrator complete callback should be played right away.
-                    return 0;
-                }
-                nextStep = mNextSteps.peek();
+            if (!mPendingOnVibratorCompleteSteps.isEmpty()) {
+                // Steps anticipated by vibrator complete callback should be played right away.
+                return 0;
             }
+            Step nextStep = mNextSteps.peek();
             return nextStep == null ? 0 : nextStep.calculateWaitTime();
         }
 
@@ -603,7 +604,10 @@
             return false;
         }
 
-        /** Returns the time in millis to wait before playing this step. */
+        /**
+         * Returns the time in millis to wait before playing this step. This is performed
+         * while holding the queue lock, so should not rely on potentially slow operations.
+         */
         public long calculateWaitTime() {
             if (startTime == Long.MAX_VALUE) {
                 // This step don't have a predefined start time, it's just marked to be executed
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4c11422..1b799df 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -733,15 +733,15 @@
         // dismissing during the task switching to keep the window focus because IME window has
         // higher window hierarchy, we don't give it focus if the next IME layering target
         // doesn't request IME visible.
-        if (w.mIsImWindow && (mImeLayeringTarget == null
+        if (w.mIsImWindow && w.isChildWindow() && (mImeLayeringTarget == null
                 || !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME))) {
-            if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG) {
-                return false;
-            }
-
-            if (w.isChildWindow()) {
-                return false;
-            }
+            return false;
+        }
+        if (w.mAttrs.type == TYPE_INPUT_METHOD_DIALOG && mImeLayeringTarget != null
+                && !mImeLayeringTarget.getRequestedVisibility(ITYPE_IME)
+                && mImeLayeringTarget.isAnimating(PARENTS | TRANSITION,
+                ANIMATION_TYPE_APP_TRANSITION)) {
+            return false;
         }
 
         final ActivityRecord activity = w.mActivityRecord;
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 672ebf1..fe1020c 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -374,7 +374,9 @@
                 // can be committed before KEYGUARD_OCCLUDE transition is handled.
                 // Set mRequestForceTransition flag to make sure that the app transition animation
                 // is applied for such case.
-                if (topActivity != null) {
+                // TODO(b/194243906): Fix this before enabling the remote keyguard animation.
+                if (WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation
+                        && topActivity != null) {
                     topActivity.mRequestForceTransition = true;
                 }
                 updateKeyguardSleepToken(DEFAULT_DISPLAY);
diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
index c12eb32..e98a4dd 100644
--- a/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appop/AppOpsStartedWatcherTest.java
@@ -64,12 +64,16 @@
                 .times(1)).onOpStarted(eq(AppOpsManager.OP_FINE_LOCATION),
                 eq(Process.myUid()), eq(getContext().getPackageName()),
                 eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
-                eq(AppOpsManager.MODE_ALLOWED));
+                eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED),
+                eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE),
+                eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE));
         inOrder.verify(listener, timeout(NOTIFICATION_TIMEOUT_MILLIS)
                 .times(1)).onOpStarted(eq(AppOpsManager.OP_CAMERA),
                 eq(Process.myUid()), eq(getContext().getPackageName()),
                 eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
-                eq(AppOpsManager.MODE_ALLOWED));
+                eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED),
+                eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE),
+                eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE));
 
         // Stop watching
         appOpsManager.stopWatchingStarted(listener);
@@ -94,7 +98,9 @@
                 .times(2)).onOpStarted(eq(AppOpsManager.OP_CAMERA),
                 eq(Process.myUid()), eq(getContext().getPackageName()),
                 eq(getContext().getAttributionTag()), eq(AppOpsManager.OP_FLAG_SELF),
-                eq(AppOpsManager.MODE_ALLOWED));
+                eq(AppOpsManager.MODE_ALLOWED), eq(OnOpStartedListener.START_TYPE_STARTED),
+                eq(AppOpsManager.ATTRIBUTION_FLAGS_NONE),
+                eq(AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE));
         verifyNoMoreInteractions(listener);
 
         // Finish up
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index 8592166a..f4d1499 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -378,6 +378,11 @@
         protected void handleLifecycleAfterAuth(boolean authenticated) {
 
         }
+
+        @Override
+        public boolean wasUserDetected() {
+            return false;
+        }
     }
 
     private static class TestAuthenticationClient extends AuthenticationClient<Object> {
@@ -407,6 +412,11 @@
         protected void handleLifecycleAfterAuth(boolean authenticated) {
 
         }
+
+        @Override
+        public boolean wasUserDetected() {
+            return false;
+        }
     }
 
     private static class TestClientMonitor2 extends TestClientMonitor {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
index 7f5f3c2..bfb0be7 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
@@ -32,6 +32,7 @@
 import static org.mockito.Mockito.withSettings;
 
 import android.content.Context;
+import android.hardware.biometrics.BiometricConstants;
 import android.os.Handler;
 import android.os.Looper;
 import android.platform.test.annotations.Presubmit;
@@ -61,6 +62,8 @@
     private Context mContext;
     @Mock
     private CoexCoordinator.Callback mCallback;
+    @Mock
+    private CoexCoordinator.ErrorCallback mErrorCallback;
 
     @Before
     public void setUp() {
@@ -255,13 +258,16 @@
         mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
         mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
 
+        // For easier reading
+        final CoexCoordinator.Callback faceCallback = mCallback;
+
         mCoexCoordinator.onAuthenticationSucceeded(0 /* currentTimeMillis */, faceClient,
-                mCallback);
-        verify(mCallback, never()).sendHapticFeedback();
-        verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
+                faceCallback);
+        verify(faceCallback, never()).sendHapticFeedback();
+        verify(faceCallback, never()).sendAuthenticationResult(anyBoolean());
         // CoexCoordinator requests the system to hold onto this AuthenticationClient until
         // UDFPS result is known
-        verify(mCallback, never()).handleLifecycleAfterAuth();
+        verify(faceCallback, never()).handleLifecycleAfterAuth();
 
         // Reset the mock
         CoexCoordinator.Callback udfpsCallback = mock(CoexCoordinator.Callback.class);
@@ -274,6 +280,8 @@
             verify(udfpsCallback).sendAuthenticationResult(true /* addAuthTokenIfStrong */);
             verify(udfpsCallback).handleLifecycleAfterAuth();
 
+            verify(faceCallback).sendAuthenticationCanceled();
+
             assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
         } else {
             mCoexCoordinator.onAuthenticationRejected(udfpsRejectedAfterMs, udfpsClient,
@@ -281,16 +289,16 @@
             if (udfpsRejectedAfterMs <= CoexCoordinator.SUCCESSFUL_AUTH_VALID_DURATION_MS) {
                 verify(udfpsCallback, never()).sendHapticFeedback();
 
-                verify(mCallback).sendHapticFeedback();
-                verify(mCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
-                verify(mCallback).handleLifecycleAfterAuth();
+                verify(faceCallback).sendHapticFeedback();
+                verify(faceCallback).sendAuthenticationResult(eq(true) /* addAuthTokenIfStrong */);
+                verify(faceCallback).handleLifecycleAfterAuth();
 
                 assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
             } else {
                 assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
 
-                verify(mCallback, never()).sendHapticFeedback();
-                verify(mCallback, never()).sendAuthenticationResult(anyBoolean());
+                verify(faceCallback, never()).sendHapticFeedback();
+                verify(faceCallback, never()).sendAuthenticationResult(anyBoolean());
 
                 verify(udfpsCallback).sendHapticFeedback();
                 verify(udfpsCallback)
@@ -485,4 +493,82 @@
         verify(callback).handleLifecycleAfterAuth();
         verify(successfulAuths).remove(eq(auth));
     }
+
+    @Test
+    public void testBiometricPrompt_FaceError() {
+        mCoexCoordinator.reset();
+
+        AuthenticationClient<?> client = mock(AuthenticationClient.class);
+        when(client.isBiometricPrompt()).thenReturn(true);
+        when(client.wasAuthAttempted()).thenReturn(true);
+
+        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
+
+        mCoexCoordinator.onAuthenticationError(client, BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+                mErrorCallback);
+        verify(mErrorCallback).sendHapticFeedback();
+    }
+
+    @Test
+    public void testKeyguard_faceAuthOnly_errorWhenBypassEnabled() {
+        testKeyguard_faceAuthOnly(true /* bypassEnabled */);
+    }
+
+    @Test
+    public void testKeyguard_faceAuthOnly_errorWhenBypassDisabled() {
+        testKeyguard_faceAuthOnly(false /* bypassEnabled */);
+    }
+
+    private void testKeyguard_faceAuthOnly(boolean bypassEnabled) {
+        mCoexCoordinator.reset();
+
+        AuthenticationClient<?> client = mock(AuthenticationClient.class);
+        when(client.isKeyguard()).thenReturn(true);
+        when(client.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
+        when(client.wasAuthAttempted()).thenReturn(true);
+        when(client.wasUserDetected()).thenReturn(true);
+
+        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, client);
+
+        mCoexCoordinator.onAuthenticationError(client, BiometricConstants.BIOMETRIC_ERROR_TIMEOUT,
+                mErrorCallback);
+        verify(mErrorCallback).sendHapticFeedback();
+    }
+
+    @Test
+    public void testKeyguard_coex_faceErrorWhenBypassEnabled() {
+        testKeyguard_coex_faceError(true /* bypassEnabled */);
+    }
+
+    @Test
+    public void testKeyguard_coex_faceErrorWhenBypassDisabled() {
+        testKeyguard_coex_faceError(false /* bypassEnabled */);
+    }
+
+    private void testKeyguard_coex_faceError(boolean bypassEnabled) {
+        mCoexCoordinator.reset();
+
+        AuthenticationClient<?> faceClient = mock(AuthenticationClient.class);
+        when(faceClient.isKeyguard()).thenReturn(true);
+        when(faceClient.isKeyguardBypassEnabled()).thenReturn(bypassEnabled);
+        when(faceClient.wasAuthAttempted()).thenReturn(true);
+        when(faceClient.wasUserDetected()).thenReturn(true);
+
+        AuthenticationClient<?> udfpsClient = mock(AuthenticationClient.class,
+                withSettings().extraInterfaces(Udfps.class));
+        when(udfpsClient.isKeyguard()).thenReturn(true);
+        when(((Udfps) udfpsClient).isPointerDown()).thenReturn(false);
+
+        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_FACE, faceClient);
+        mCoexCoordinator.addAuthenticationClient(SENSOR_TYPE_UDFPS, udfpsClient);
+
+        mCoexCoordinator.onAuthenticationError(faceClient,
+                BiometricConstants.BIOMETRIC_ERROR_TIMEOUT, mErrorCallback);
+
+        if (bypassEnabled) {
+            verify(mErrorCallback).sendHapticFeedback();
+        } else {
+            verify(mErrorCallback, never()).sendHapticFeedback();
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index a205a1d..1ac28ab 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -1340,11 +1340,19 @@
                 createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
         director.start(createMockSensorManager());
 
-        ArgumentCaptor<ProximityActiveListener> captor =
+        ArgumentCaptor<ProximityActiveListener> ProximityCaptor =
                 ArgumentCaptor.forClass(ProximityActiveListener.class);
         verify(mSensorManagerInternalMock).addProximityActiveListener(any(Executor.class),
-                captor.capture());
-        ProximityActiveListener listener = captor.getValue();
+                ProximityCaptor.capture());
+        ProximityActiveListener proximityListener = ProximityCaptor.getValue();
+
+        ArgumentCaptor<DisplayListener> DisplayCaptor =
+                ArgumentCaptor.forClass(DisplayListener.class);
+        verify(mInjector).registerDisplayListener(DisplayCaptor.capture(), any(Handler.class),
+                eq(DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+                        | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+                        | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
+        DisplayListener displayListener = DisplayCaptor.getValue();
 
         // Verify that there is no proximity vote initially
         Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
@@ -1353,13 +1361,38 @@
         when(mDisplayManagerInternalMock.getRefreshRateForDisplayAndSensor(eq(DISPLAY_ID), eq(null),
                   eq(Sensor.STRING_TYPE_PROXIMITY))).thenReturn(new RefreshRateRange(60, 60));
 
+        when(mInjector.isDozeState(any(Display.class))).thenReturn(false);
+
         // Set the proximity to active and verify that we added a vote.
-        listener.onProximityActive(true);
+        proximityListener.onProximityActive(true);
+        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+        assertVoteForRefreshRate(vote, 60.f);
+
+        // Set the display state to doze and verify that the vote is gone
+        when(mInjector.isDozeState(any(Display.class))).thenReturn(true);
+        displayListener.onDisplayAdded(DISPLAY_ID);
+        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+        assertNull(vote);
+
+        // Set the display state to on and verify that we added the vote back.
+        when(mInjector.isDozeState(any(Display.class))).thenReturn(false);
+        displayListener.onDisplayChanged(DISPLAY_ID);
+        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+        assertVoteForRefreshRate(vote, 60.f);
+
+        // Set the display state to doze and verify that the vote is gone
+        when(mInjector.isDozeState(any(Display.class))).thenReturn(true);
+        displayListener.onDisplayAdded(DISPLAY_ID);
+        vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
+        assertNull(vote);
+
+        // Remove the display to cause the doze state to be removed
+        displayListener.onDisplayRemoved(DISPLAY_ID);
         vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
         assertVoteForRefreshRate(vote, 60.f);
 
         // Turn prox off and verify vote is gone.
-        listener.onProximityActive(false);
+        proximityListener.onProximityActive(false);
         vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_PROXIMITY);
         assertNull(vote);
     }
@@ -1710,6 +1743,11 @@
             return null;
         }
 
+        @Override
+        public boolean isDozeState(Display d) {
+            return false;
+        }
+
         void notifyPeakRefreshRateChanged() {
             if (mPeakRefreshRateObserver != null) {
                 mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
diff --git a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
index 61b5c2b..4cc4d55 100644
--- a/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
+++ b/services/tests/servicestests/src/com/android/server/vibrator/VibrationThreadTest.java
@@ -83,7 +83,7 @@
 @Presubmit
 public class VibrationThreadTest {
 
-    private static final int TEST_TIMEOUT_MILLIS = 1_000;
+    private static final int TEST_TIMEOUT_MILLIS = 900;
     private static final int UID = Process.ROOT_UID;
     private static final int VIBRATOR_ID = 1;
     private static final String PACKAGE_NAME = "package";
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index c60b8dc..12fc2f4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -2223,6 +2223,9 @@
         // request IME visible.
         final WindowState nextImeAppTarget =
                 createWindow(null, TYPE_BASE_APPLICATION, mDisplayContent, "nextImeAppTarget");
+        spyOn(nextImeAppTarget);
+        doReturn(true).when(nextImeAppTarget).isAnimating(PARENTS | TRANSITION,
+                ANIMATION_TYPE_APP_TRANSITION);
         mDisplayContent.setImeLayeringTarget(nextImeAppTarget);
         assertNotEquals(imeMenuDialog, mDisplayContent.findFocusedWindow());
     }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 965f126..734172f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -36,6 +36,7 @@
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
 import android.hardware.soundtrigger.SoundTrigger;
 import android.media.AudioFormat;
+import android.media.AudioManagerInternal;
 import android.media.permission.Identity;
 import android.media.permission.PermissionUtil;
 import android.os.Binder;
@@ -44,6 +45,7 @@
 import android.os.IRemoteCallback;
 import android.os.ParcelFileDescriptor;
 import android.os.PersistableBundle;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SharedMemory;
@@ -275,6 +277,7 @@
             LocalServices.getService(PermissionManagerServiceInternal.class)
                     .setHotwordDetectionServiceProvider(null);
             mIdentity = null;
+            updateServiceUidForAudioPolicy(Process.INVALID_UID);
         }
         mCancellationTaskFuture.cancel(/* may interrupt */ true);
         if (mAudioFlinger != null) {
@@ -893,6 +896,8 @@
         connection.run(service -> service.ping(new IRemoteCallback.Stub() {
             @Override
             public void sendResult(Bundle bundle) throws RemoteException {
+                // TODO: Exit if the service has been unbound already (though there's a very low
+                // chance this happens).
                 if (DEBUG) {
                     Slog.d(TAG, "updating hotword UID " + Binder.getCallingUid());
                 }
@@ -902,10 +907,21 @@
                 LocalServices.getService(PermissionManagerServiceInternal.class)
                         .setHotwordDetectionServiceProvider(() -> uid);
                 mIdentity = new HotwordDetectionServiceIdentity(uid, mVoiceInteractionServiceUid);
+                updateServiceUidForAudioPolicy(uid);
             }
         }));
     }
 
+    private void updateServiceUidForAudioPolicy(int uid) {
+        mScheduledExecutorService.execute(() -> {
+            final AudioManagerInternal audioManager =
+                    LocalServices.getService(AudioManagerInternal.class);
+            if (audioManager != null) {
+                audioManager.setHotwordDetectionServiceUid(uid);
+            }
+        });
+    }
+
     private static void bestEffortClose(Closeable closeable) {
         try {
             closeable.close();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 71541ad..9ea2b7b 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1896,17 +1896,19 @@
 
                         String serviceComponentName = serviceInfo.getComponentName()
                                 .flattenToShortString();
-
-                        String serviceRecognizerName = new ComponentName(pkg,
-                                voiceInteractionServiceInfo.getRecognitionService())
-                                .flattenToShortString();
+                        if (voiceInteractionServiceInfo.getRecognitionService() == null) {
+                            Slog.e(TAG, "The RecognitionService must be set to avoid boot "
+                                    + "loop on earlier platform version. Also make sure that this "
+                                    + "is a valid RecognitionService when running on Android 11 "
+                                    + "or earlier.");
+                            serviceComponentName = "";
+                        }
 
                         Settings.Secure.putStringForUser(getContext().getContentResolver(),
                                 Settings.Secure.ASSISTANT, serviceComponentName, userId);
                         Settings.Secure.putStringForUser(getContext().getContentResolver(),
                                 Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName,
                                 userId);
-
                         return;
                     }
 
@@ -1947,6 +1949,29 @@
             }
         }
 
+        private void resetServicesIfNoRecognitionService(ComponentName serviceComponent,
+                int userHandle) {
+            for (ResolveInfo resolveInfo : queryInteractorServices(userHandle,
+                    serviceComponent.getPackageName())) {
+                VoiceInteractionServiceInfo serviceInfo =
+                        new VoiceInteractionServiceInfo(
+                                mContext.getPackageManager(),
+                                resolveInfo.serviceInfo);
+                if (!serviceInfo.getSupportsAssist()) {
+                    continue;
+                }
+                if (serviceInfo.getRecognitionService() == null) {
+                    Slog.e(TAG, "The RecognitionService must be set to "
+                            + "avoid boot loop on earlier platform version. "
+                            + "Also make sure that this is a valid "
+                            + "RecognitionService when running on Android 11 "
+                            + "or earlier.");
+                    setCurInteractor(null, userHandle);
+                    resetCurAssistant(userHandle);
+                }
+            }
+        }
+
         PackageMonitor mPackageMonitor = new PackageMonitor() {
             @Override
             public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
@@ -2090,6 +2115,7 @@
 
                         change = isPackageAppearing(curInteractor.getPackageName());
                         if (change != PACKAGE_UNCHANGED) {
+                            resetServicesIfNoRecognitionService(curInteractor, userHandle);
                             // If current interactor is now appearing, for any reason, then
                             // restart our connection with it.
                             if (mImpl != null && curInteractor.getPackageName().equals(
@@ -2112,6 +2138,13 @@
                             initForUser(userHandle);
                             return;
                         }
+                        change = isPackageAppearing(curAssistant.getPackageName());
+                        if (change != PACKAGE_UNCHANGED) {
+                            // It is possible to update Assistant without a voice interactor to one
+                            // with a voice-interactor. We should make sure the recognition service
+                            // is set to avoid boot loop.
+                            resetServicesIfNoRecognitionService(curAssistant, userHandle);
+                        }
                     }
 
                     // There is no interactor, so just deal with a simple recognizer.
diff --git a/telephony/OWNERS b/telephony/OWNERS
index 628c480..4df8a4b 100644
--- a/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -4,13 +4,14 @@
 breadley@google.com
 fionaxu@google.com
 jackyu@google.com
-hallliu@google.com
 rgreenwalt@google.com
 tgunn@google.com
 jminjie@google.com
 shuoq@google.com
-refuhoo@google.com
 nazaninb@google.com
 sarahchin@google.com
-dbright@google.com
 xiaotonj@google.com
+huiwang@google.com
+jayachandranc@google.com
+chinmayd@google.com
+amruthr@google.com
diff --git a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
index c18ab33..f004824 100644
--- a/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
+++ b/telephony/java/android/telephony/ims/aidl/SipDelegateAidlWrapper.java
@@ -193,6 +193,10 @@
         return mDelegateBinder;
     }
 
+    public ISipDelegateStateCallback getStateCallbackBinder() {
+        return mStateBinder;
+    }
+
     private void notifyLocalMessageFailedToBeReceived(SipMessage m, int reason) {
         String transactionId = m.getViaBranchParameter();
         SipDelegate d = mDelegate;
diff --git a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
index 1f74c09..13ea9973 100644
--- a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java
@@ -21,6 +21,7 @@
 import android.annotation.SystemApi;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.telephony.ims.DelegateMessageCallback;
 import android.telephony.ims.DelegateRequest;
 import android.telephony.ims.DelegateStateCallback;
@@ -33,6 +34,7 @@
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.concurrent.Executor;
 
@@ -49,10 +51,15 @@
 public class SipTransportImplBase {
     private static final String LOG_TAG = "SipTransportIB";
 
-    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+    private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
         @Override
         public void binderDied() {
-            mBinderExecutor.execute(() -> binderDiedInternal());
+            // Clean up all binders in this case.
+            mBinderExecutor.execute(() -> binderDiedInternal(null));
+        }
+        @Override
+        public void binderDied(IBinder who) {
+            mBinderExecutor.execute(() -> binderDiedInternal(who));
         }
     };
 
@@ -142,6 +149,7 @@
             ISipDelegateStateCallback cb, ISipDelegateMessageCallback mc) {
         SipDelegateAidlWrapper wrapper = new SipDelegateAidlWrapper(mBinderExecutor, cb, mc);
         mDelegates.add(wrapper);
+        linkDeathRecipient(wrapper);
         createSipDelegate(subId, r, wrapper, wrapper);
     }
 
@@ -155,6 +163,7 @@
         }
 
         if (result != null) {
+            unlinkDeathRecipient(result);
             mDelegates.remove(result);
             destroySipDelegate(result.getDelegate(), reason);
         } else {
@@ -163,12 +172,37 @@
         }
     }
 
-    private void binderDiedInternal() {
-        for (SipDelegateAidlWrapper w : mDelegates) {
-            destroySipDelegate(w.getDelegate(),
-                    SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+    private void linkDeathRecipient(SipDelegateAidlWrapper w) {
+        try {
+            w.getStateCallbackBinder().asBinder().linkToDeath(mDeathRecipient, 0);
+        } catch (RemoteException e) {
+            Log.w(LOG_TAG, "linkDeathRecipient, remote process already died, cleaning up.");
+            mDeathRecipient.binderDied(w.getStateCallbackBinder().asBinder());
         }
-        mDelegates.clear();
+    }
+
+    private void unlinkDeathRecipient(SipDelegateAidlWrapper w) {
+        try {
+            w.getStateCallbackBinder().asBinder().unlinkToDeath(mDeathRecipient, 0);
+        } catch (NoSuchElementException e) {
+            // Ignore this case.
+        }
+    }
+
+    private void binderDiedInternal(IBinder who) {
+        for (SipDelegateAidlWrapper w : mDelegates) {
+            // If the binder itself was not given from the platform, just clean up all binders.
+            if (who == null || w.getStateCallbackBinder().asBinder().equals(who))  {
+                Log.w(LOG_TAG, "Binder death detected for " + w + ", calling destroy and "
+                        + "removing.");
+                mDelegates.remove(w);
+                destroySipDelegate(w.getDelegate(),
+                        SipDelegateManager.SIP_DELEGATE_DESTROY_REASON_SERVICE_DEAD);
+                return;
+            }
+        }
+        Log.w(LOG_TAG, "Binder death detected for IBinder " + who + ", but couldn't find matching "
+                + "SipDelegate");
     }
 
     /**