Merge "PackageSetting now owns its PackageUserState" into sc-dev
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/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..6c2d6a1 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1242,7 +1242,7 @@
             mBlastSurfaceControl.setTransformHint(mTransformHint);
             if (mBlastBufferQueue != null) {
                 mBlastBufferQueue.update(mBlastSurfaceControl, mSurfaceWidth, mSurfaceHeight,
-                        mFormat);
+                        mFormat, transaction);
             }
         } else {
             transaction.setBufferSize(mSurfaceControl, mSurfaceWidth, mSurfaceHeight);
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/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/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/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/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/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/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/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/biometrics/sensors/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
index f4327e8..705b3aa 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AuthenticationClient.java
@@ -180,7 +180,8 @@
                 + ", isBP: " + isBiometricPrompt()
                 + ", listener: " + listener
                 + ", requireConfirmation: " + mRequireConfirmation
-                + ", user: " + getTargetUserId());
+                + ", user: " + getTargetUserId()
+                + ", clientMonitor: " + toString());
 
         final PerformanceTracker pm = PerformanceTracker.getInstanceForSensorId(getSensorId());
         if (isCryptoOperation()) {
@@ -304,6 +305,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 +344,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);
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..6d32fde 100644
--- a/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/CoexCoordinator.java
@@ -73,6 +73,11 @@
          * from scheduler if auth was successful).
          */
         void handleLifecycleAfterAuth();
+
+        /**
+         * Requests the owner to notify the caller that authentication was canceled.
+         */
+        void sendAuthenticationCanceled();
     }
 
     private static CoexCoordinator sInstance;
@@ -356,7 +361,11 @@
     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 +376,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/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ee44c10..031910a 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");
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/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index f2f1926..11a0fba 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -32,6 +32,10 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
 
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.StatusBarManager;
@@ -211,7 +215,7 @@
     InsetsState getInsetsForWindow(WindowState target) {
         final InsetsState originalState = mStateController.getInsetsForWindow(target);
         final InsetsState state = adjustVisibilityForTransientTypes(originalState);
-        return target.mIsImWindow ? adjustVisibilityForIme(state, state == originalState) : state;
+        return adjustVisibilityForIme(target, state, state == originalState);
     }
 
     /**
@@ -241,16 +245,38 @@
         return state;
     }
 
-    // Navigation bar insets is always visible to IME.
-    private static InsetsState adjustVisibilityForIme(InsetsState originalState,
+    private InsetsState adjustVisibilityForIme(WindowState w, InsetsState originalState,
             boolean copyState) {
-        final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
-        if (originalNavSource != null && !originalNavSource.isVisible()) {
-            final InsetsState state = copyState ? new InsetsState(originalState) : originalState;
-            final InsetsSource navSource = new InsetsSource(originalNavSource);
-            navSource.setVisible(true);
-            state.addSource(navSource);
-            return state;
+        if (w.mIsImWindow) {
+            // Navigation bar insets is always visible to IME.
+            final InsetsSource originalNavSource = originalState.peekSource(ITYPE_NAVIGATION_BAR);
+            if (originalNavSource != null && !originalNavSource.isVisible()) {
+                final InsetsState state = copyState ? new InsetsState(originalState)
+                        : originalState;
+                final InsetsSource navSource = new InsetsSource(originalNavSource);
+                navSource.setVisible(true);
+                state.addSource(navSource);
+                return state;
+            }
+        } else if (w.mActivityRecord != null && !w.mActivityRecord.mLastImeShown) {
+            // During switching tasks with gestural navigation, if the IME is attached to
+            // one app window on that time, even the next app window is behind the IME window,
+            // conceptually the window should not receive the IME insets if the next window is
+            // not eligible IME requester and ready to show IME on top of it.
+            final boolean shouldImeAttachedToApp = mDisplayContent.shouldImeAttachedToApp();
+            final InsetsSource originalImeSource = originalState.peekSource(ITYPE_IME);
+
+            if (originalImeSource != null && shouldImeAttachedToApp
+                    && (w.isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS)
+                            || !w.getRequestedVisibility(ITYPE_IME))) {
+                final InsetsState state = copyState ? new InsetsState(originalState)
+                        : originalState;
+
+                final InsetsSource imeSource = new InsetsSource(originalImeSource);
+                imeSource.setVisible(false);
+                state.addSource(imeSource);
+                return state;
+            }
         }
         return originalState;
     }
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/CoexCoordinatorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CoexCoordinatorTest.java
index 7f5f3c2..1263f7b 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
@@ -255,13 +255,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 +277,8 @@
             verify(udfpsCallback).sendAuthenticationResult(true /* addAuthTokenIfStrong */);
             verify(udfpsCallback).handleLifecycleAfterAuth();
 
+            verify(faceCallback).sendAuthenticationCanceled();
+
             assertTrue(mCoexCoordinator.mSuccessfulAuths.isEmpty());
         } else {
             mCoexCoordinator.onAuthenticationRejected(udfpsRejectedAfterMs, udfpsClient,
@@ -281,16 +286,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)
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/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index 92b670e..3a50bb0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -53,6 +53,9 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL;
 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
+import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
 import static com.android.server.wm.WindowContainer.SYNC_STATE_WAITING_FOR_DRAW;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -891,6 +894,36 @@
         assertTrue(mAppWindow.getInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR));
     }
 
+    @UseTestDisplay(addWindows = W_INPUT_METHOD)
+    @Test
+    public void testAdjustImeInsetsVisibilityWhenTaskSwitchIsAnimating() {
+        final WindowState app = createWindow(null, TYPE_APPLICATION, "app");
+        final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2");
+        final InsetsStateController controller = mDisplayContent.getInsetsStateController();
+        controller.getImeSourceProvider().setWindow(mImeWindow, null, null);
+
+        // Simulate app requests IME with updating all windows Insets State when IME is above app.
+        mDisplayContent.setImeLayeringTarget(app);
+        mDisplayContent.setImeInputTarget(app);
+        assertTrue(mDisplayContent.shouldImeAttachedToApp());
+        controller.getImeSourceProvider().scheduleShowImePostLayout(app);
+        controller.getImeSourceProvider().getSource().setVisible(true);
+        controller.updateAboveInsetsState(mImeWindow, false);
+
+        // Simulate task switching animation happens when switching app to app2.
+        spyOn(app);
+        spyOn(app2);
+        doReturn(true).when(app).isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS);
+        doReturn(true).when(app2).isAnimating(PARENTS | TRANSITION, ANIMATION_TYPE_RECENTS);
+        app.mActivityRecord.mLastImeShown = true;
+
+        // Verify the IME insets is visible on app, but not for app2 during task animating.
+        InsetsState stateApp = app.getInsetsState();
+        InsetsState stateApp2 = app2.getInsetsState();
+        assertTrue(stateApp.getSource(ITYPE_IME).isVisible());
+        assertFalse(stateApp2.getSource(ITYPE_IME).isVisible());
+    }
+
     @UseTestDisplay(addWindows = { W_ACTIVITY })
     @Test
     public void testUpdateImeControlTargetWhenLeavingMultiWindow() {
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.