Merge "System MR2: Fix bug on onTransfer and on getting initial routes" into sc-dev
diff --git a/core/api/current.txt b/core/api/current.txt
index 4aa38d6..97f9855 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -52401,6 +52401,17 @@
     method @Nullable @WorkerThread public android.view.translation.TranslationResponse translate(@NonNull android.view.translation.TranslationRequest);
   }
 
+  public final class UiTranslationManager {
+    method public void registerUiTranslationStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.view.translation.UiTranslationStateCallback);
+    method public void unregisterUiTranslationStateCallback(@NonNull android.view.translation.UiTranslationStateCallback);
+  }
+
+  public interface UiTranslationStateCallback {
+    method public void onFinished();
+    method public void onPaused();
+    method public void onStarted(@NonNull String, @NonNull String);
+  }
+
   public final class ViewTranslationRequest implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public android.view.autofill.AutofillId getAutofillId();
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 39e259d..1d1303f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1795,6 +1795,7 @@
 
   public final class UsageStats implements android.os.Parcelable {
     method public int getAppLaunchCount();
+    method public long getLastTimeComponentUsed();
   }
 
   public final class UsageStatsManager {
@@ -3070,6 +3071,7 @@
     field public final float reduceBrightColorsOffset;
     field public final int reduceBrightColorsStrength;
     field public final long timeStamp;
+    field @NonNull public final String uniqueDisplayId;
   }
 
   public final class BrightnessConfiguration implements android.os.Parcelable {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 1587475..d4b3f16 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -28,6 +28,7 @@
     field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
     field public static final String NETWORK_STACK = "android.permission.NETWORK_STACK";
     field public static final String OVERRIDE_DISPLAY_MODE_REQUESTS = "android.permission.OVERRIDE_DISPLAY_MODE_REQUESTS";
+    field public static final String QUERY_AUDIO_STATE = "android.permission.QUERY_AUDIO_STATE";
     field public static final String QUERY_USERS = "android.permission.QUERY_USERS";
     field public static final String READ_CELL_BROADCASTS = "android.permission.READ_CELL_BROADCASTS";
     field public static final String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE";
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index dcecd90..5d50c5d7 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -20,6 +20,7 @@
 import static android.app.usage.UsageEvents.Event.ACTIVITY_PAUSED;
 import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
 import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
+import static android.app.usage.UsageEvents.Event.APP_COMPONENT_USED;
 import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
 import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageEvents.Event.END_OF_DAY;
@@ -109,6 +110,13 @@
     public long mTotalTimeForegroundServiceUsed;
 
     /**
+     * Last time this package's component is used, measured in milliseconds since the epoch.
+     * See {@link UsageEvents.Event#APP_COMPONENT_USED}
+     * @hide
+     */
+    public long mLastTimeComponentUsed;
+
+    /**
      * {@hide}
      */
     @UnsupportedAppUsage
@@ -166,6 +174,7 @@
         mEndTimeStamp = stats.mEndTimeStamp;
         mLastTimeUsed = stats.mLastTimeUsed;
         mLastTimeVisible = stats.mLastTimeVisible;
+        mLastTimeComponentUsed = stats.mLastTimeComponentUsed;
         mLastTimeForegroundServiceUsed = stats.mLastTimeForegroundServiceUsed;
         mTotalTimeInForeground = stats.mTotalTimeInForeground;
         mTotalTimeVisible = stats.mTotalTimeVisible;
@@ -265,6 +274,16 @@
     }
 
     /**
+     * Get the last time this package's component was used, measured in milliseconds since the
+     * epoch.
+     * @hide
+     */
+    @SystemApi
+    public long getLastTimeComponentUsed() {
+        return mLastTimeComponentUsed;
+    }
+
+    /**
      * Returns the number of times the app was launched as an activity from outside of the app.
      * Excludes intra-app activity transitions.
      * @hide
@@ -323,6 +342,7 @@
             mergeEventMap(mForegroundServices, right.mForegroundServices);
             mLastTimeUsed = Math.max(mLastTimeUsed, right.mLastTimeUsed);
             mLastTimeVisible = Math.max(mLastTimeVisible, right.mLastTimeVisible);
+            mLastTimeComponentUsed = Math.max(mLastTimeComponentUsed, right.mLastTimeComponentUsed);
             mLastTimeForegroundServiceUsed = Math.max(mLastTimeForegroundServiceUsed,
                     right.mLastTimeForegroundServiceUsed);
         }
@@ -598,6 +618,9 @@
                     mLastTimeVisible = timeStamp;
                 }
                 break;
+            case APP_COMPONENT_USED:
+                mLastTimeComponentUsed = timeStamp;
+                break;
             default:
                 break;
         }
@@ -620,6 +643,7 @@
         dest.writeLong(mEndTimeStamp);
         dest.writeLong(mLastTimeUsed);
         dest.writeLong(mLastTimeVisible);
+        dest.writeLong(mLastTimeComponentUsed);
         dest.writeLong(mLastTimeForegroundServiceUsed);
         dest.writeLong(mTotalTimeInForeground);
         dest.writeLong(mTotalTimeVisible);
@@ -674,6 +698,7 @@
             stats.mEndTimeStamp = in.readLong();
             stats.mLastTimeUsed = in.readLong();
             stats.mLastTimeVisible = in.readLong();
+            stats.mLastTimeComponentUsed = in.readLong();
             stats.mLastTimeForegroundServiceUsed = in.readLong();
             stats.mTotalTimeInForeground = in.readLong();
             stats.mTotalTimeVisible = in.readLong();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 5cf83ac..adf9ff3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1954,8 +1954,8 @@
 
     /**
      * Activity action: Launch UI to show information about the usage
-     * of a given permission. This action would be handled by apps that
-     * want to show details about how and why given permission is being
+     * of a given permission group. This action would be handled by apps that
+     * want to show details about how and why given permission group is being
      * used.
      * <p>
      * <strong>Important:</strong>You must protect the activity that handles
@@ -1965,7 +1965,7 @@
      * activities that are not properly protected.
      *
      * <p>
-     * Input: {@code android.intent.extra.PERMISSION_NAME} specifies the permission
+     * Input: {@link android.Manifest.permission_group} specifies the permission group
      * for which the launched UI would be targeted.
      * </p>
      * <p>
diff --git a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
index 0b81c6c..909f456 100644
--- a/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
+++ b/core/java/android/hardware/biometrics/SensorPropertiesInternal.java
@@ -31,23 +31,31 @@
     public final int sensorId;
     @SensorProperties.Strength public final int sensorStrength;
     public final int maxEnrollmentsPerUser;
+    public final boolean resetLockoutRequiresHardwareAuthToken;
+    public final boolean resetLockoutRequiresChallenge;
 
     public static SensorPropertiesInternal from(@NonNull SensorPropertiesInternal prop) {
         return new SensorPropertiesInternal(prop.sensorId, prop.sensorStrength,
-                prop.maxEnrollmentsPerUser);
+                prop.maxEnrollmentsPerUser, prop.resetLockoutRequiresHardwareAuthToken,
+                prop.resetLockoutRequiresChallenge);
     }
 
     protected SensorPropertiesInternal(int sensorId, @SensorProperties.Strength int sensorStrength,
-            int maxEnrollmentsPerUser) {
+            int maxEnrollmentsPerUser, boolean resetLockoutRequiresHardwareAuthToken,
+            boolean resetLockoutRequiresChallenge) {
         this.sensorId = sensorId;
         this.sensorStrength = sensorStrength;
         this.maxEnrollmentsPerUser = maxEnrollmentsPerUser;
+        this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
+        this.resetLockoutRequiresChallenge = resetLockoutRequiresChallenge;
     }
 
     protected SensorPropertiesInternal(Parcel in) {
         sensorId = in.readInt();
         sensorStrength = in.readInt();
         maxEnrollmentsPerUser = in.readInt();
+        resetLockoutRequiresHardwareAuthToken = in.readBoolean();
+        resetLockoutRequiresChallenge = in.readBoolean();
     }
 
     public static final Creator<SensorPropertiesInternal> CREATOR =
@@ -73,6 +81,8 @@
         dest.writeInt(sensorId);
         dest.writeInt(sensorStrength);
         dest.writeInt(maxEnrollmentsPerUser);
+        dest.writeBoolean(resetLockoutRequiresHardwareAuthToken);
+        dest.writeBoolean(resetLockoutRequiresChallenge);
     }
 
     @Override
diff --git a/core/java/android/hardware/display/BrightnessChangeEvent.java b/core/java/android/hardware/display/BrightnessChangeEvent.java
index a6c6b46..6b7d8c3 100644
--- a/core/java/android/hardware/display/BrightnessChangeEvent.java
+++ b/core/java/android/hardware/display/BrightnessChangeEvent.java
@@ -47,6 +47,10 @@
      * @hide */
     public final int userId;
 
+    /** The unique id of the screen on which the brightness was changed */
+    @NonNull
+    public final String uniqueDisplayId;
+
     /** Lux values of recent sensor data */
     public final float[] luxValues;
 
@@ -120,15 +124,16 @@
 
     /** @hide */
     private BrightnessChangeEvent(float brightness, long timeStamp, String packageName,
-            int userId, float[] luxValues, long[] luxTimestamps, float batteryLevel,
-            float powerBrightnessFactor, boolean nightMode, int colorTemperature,
-            boolean reduceBrightColors, int reduceBrightColorsStrength,
+            int userId, String uniqueDisplayId, float[] luxValues, long[] luxTimestamps,
+            float batteryLevel, float powerBrightnessFactor, boolean nightMode,
+            int colorTemperature, boolean reduceBrightColors, int reduceBrightColorsStrength,
             float reduceBrightColorsOffset, float lastBrightness, boolean isDefaultBrightnessConfig,
             boolean isUserSetBrightness, long[] colorValueBuckets, long colorSampleDuration) {
         this.brightness = brightness;
         this.timeStamp = timeStamp;
         this.packageName = packageName;
         this.userId = userId;
+        this.uniqueDisplayId = uniqueDisplayId;
         this.luxValues = luxValues;
         this.luxTimestamps = luxTimestamps;
         this.batteryLevel = batteryLevel;
@@ -151,6 +156,7 @@
         this.timeStamp = other.timeStamp;
         this.packageName = redactPackage ? null : other.packageName;
         this.userId = other.userId;
+        this.uniqueDisplayId = other.uniqueDisplayId;
         this.luxValues = other.luxValues;
         this.luxTimestamps = other.luxTimestamps;
         this.batteryLevel = other.batteryLevel;
@@ -172,6 +178,7 @@
         timeStamp = source.readLong();
         packageName = source.readString();
         userId = source.readInt();
+        uniqueDisplayId = source.readString();
         luxValues = source.createFloatArray();
         luxTimestamps = source.createLongArray();
         batteryLevel = source.readFloat();
@@ -209,6 +216,7 @@
         dest.writeLong(timeStamp);
         dest.writeString(packageName);
         dest.writeInt(userId);
+        dest.writeString(uniqueDisplayId);
         dest.writeFloatArray(luxValues);
         dest.writeLongArray(luxTimestamps);
         dest.writeFloat(batteryLevel);
@@ -231,6 +239,7 @@
         private long mTimeStamp;
         private String mPackageName;
         private int mUserId;
+        private String mUniqueDisplayId;
         private float[] mLuxValues;
         private long[] mLuxTimestamps;
         private float mBatteryLevel;
@@ -270,6 +279,12 @@
             return this;
         }
 
+        /** {@see BrightnessChangeEvent#uniqueScreenId} */
+        public Builder setUniqueDisplayId(String uniqueId) {
+            mUniqueDisplayId = uniqueId;
+            return this;
+        }
+
         /** {@see BrightnessChangeEvent#luxValues} */
         public Builder setLuxValues(float[] luxValues) {
             mLuxValues = luxValues;
@@ -354,11 +369,11 @@
         /** Builds a BrightnessChangeEvent */
         public BrightnessChangeEvent build() {
             return new BrightnessChangeEvent(mBrightness, mTimeStamp,
-                    mPackageName, mUserId, mLuxValues, mLuxTimestamps, mBatteryLevel,
-                    mPowerBrightnessFactor, mNightMode, mColorTemperature, mReduceBrightColors,
-                    mReduceBrightColorsStrength, mReduceBrightColorsOffset, mLastBrightness,
-                    mIsDefaultBrightnessConfig, mIsUserSetBrightness, mColorValueBuckets,
-                    mColorSampleDuration);
+                    mPackageName, mUserId, mUniqueDisplayId, mLuxValues, mLuxTimestamps,
+                    mBatteryLevel, mPowerBrightnessFactor, mNightMode, mColorTemperature,
+                    mReduceBrightColors, mReduceBrightColorsStrength, mReduceBrightColorsOffset,
+                    mLastBrightness, mIsDefaultBrightnessConfig, mIsUserSetBrightness,
+                    mColorValueBuckets, mColorSampleDuration);
         }
     }
 }
diff --git a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
index b9c0d12..34cbcb4 100644
--- a/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
+++ b/core/java/android/hardware/face/FaceSensorPropertiesInternal.java
@@ -41,8 +41,11 @@
      */
     public FaceSensorPropertiesInternal(int sensorId, @SensorProperties.Strength int strength,
             int maxEnrollmentsPerUser, boolean supportsFaceDetection,
-            boolean supportsSelfIllumination) {
-        super(sensorId, strength, maxEnrollmentsPerUser);
+            boolean supportsSelfIllumination, boolean resetLockoutRequiresChallenge) {
+        // resetLockout is managed by the HAL and requires a HardwareAuthToken for all face
+        // HAL interfaces (IBiometricsFace@1.0 HIDL and IFace@1.0 AIDL).
+        super(sensorId, strength, maxEnrollmentsPerUser,
+                true /* resetLockoutRequiresHardwareAuthToken */, resetLockoutRequiresChallenge);
         this.supportsFaceDetection = supportsFaceDetection;
         this.supportsSelfIllumination = supportsSelfIllumination;
     }
diff --git a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
index 51addc9..adc61a7 100644
--- a/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
+++ b/core/java/android/hardware/fingerprint/FingerprintSensorPropertiesInternal.java
@@ -36,12 +36,6 @@
     public final @FingerprintSensorProperties.SensorType int sensorType;
 
     /**
-     * IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT
-     * cannot be checked
-     */
-    public final boolean resetLockoutRequiresHardwareAuthToken;
-
-    /**
      * The location of the center of the sensor if applicable. For example, sensors of type
      * {@link FingerprintSensorProperties#TYPE_UDFPS_OPTICAL} would report this value as the
      * distance in pixels, measured from the left edge of the screen.
@@ -68,9 +62,13 @@
             @FingerprintSensorProperties.SensorType int sensorType,
             boolean resetLockoutRequiresHardwareAuthToken, int sensorLocationX, int sensorLocationY,
             int sensorRadius) {
-        super(sensorId, strength, maxEnrollmentsPerUser);
+        // IBiometricsFingerprint@2.1 handles lockout in the framework, so the challenge is not
+        // required as it can only be generated/attested/verified by TEE components.
+        // IFingerprint@1.0 handles lockout below the HAL, but does not require a challenge. See
+        // the HAL interface for more details.
+        super(sensorId, strength, maxEnrollmentsPerUser, resetLockoutRequiresHardwareAuthToken,
+                false /* resetLockoutRequiresChallenge */);
         this.sensorType = sensorType;
-        this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
         this.sensorLocationX = sensorLocationX;
         this.sensorLocationY = sensorLocationY;
         this.sensorRadius = sensorRadius;
@@ -98,9 +96,9 @@
             @SensorProperties.Strength int strength, int maxEnrollmentsPerUser,
             @FingerprintSensorProperties.SensorType int sensorType,
             boolean resetLockoutRequiresHardwareAuthToken) {
-        super(sensorId, strength, maxEnrollmentsPerUser);
+        super(sensorId, strength, maxEnrollmentsPerUser, resetLockoutRequiresHardwareAuthToken,
+                false /* resetLockoutRequiresChallenge */);
         this.sensorType = sensorType;
-        this.resetLockoutRequiresHardwareAuthToken = resetLockoutRequiresHardwareAuthToken;
 
         int[] props = context.getResources().getIntArray(
                 com.android.internal.R.array.config_udfps_sensor_props);
@@ -119,7 +117,6 @@
     protected FingerprintSensorPropertiesInternal(Parcel in) {
         super(in);
         sensorType = in.readInt();
-        resetLockoutRequiresHardwareAuthToken = in.readBoolean();
         sensorLocationX = in.readInt();
         sensorLocationY = in.readInt();
         sensorRadius = in.readInt();
@@ -147,7 +144,6 @@
     public void writeToParcel(Parcel dest, int flags) {
         super.writeToParcel(dest, flags);
         dest.writeInt(sensorType);
-        dest.writeBoolean(resetLockoutRequiresHardwareAuthToken);
         dest.writeInt(sensorLocationX);
         dest.writeInt(sensorLocationY);
         dest.writeInt(sensorRadius);
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index df4ade0..d89c3d5 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -21,6 +21,7 @@
 import android.util.Slog;
 
 import java.io.PrintWriter;
+import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
 /**
@@ -354,6 +355,23 @@
     }
 
     /**
+     * Performs {@code action} on each callback and associated cookie, calling {@link
+     * #beginBroadcast()}/{@link #finishBroadcast()} before/after looping.
+     *
+     * @hide
+     */
+    public <C> void broadcast(BiConsumer<E, C> action) {
+        int itemCount = beginBroadcast();
+        try {
+            for (int i = 0; i < itemCount; i++) {
+                action.accept(getBroadcastItem(i), (C) getBroadcastCookie(i));
+            }
+        } finally {
+            finishBroadcast();
+        }
+    }
+
+    /**
      * Returns the number of registered callbacks. Note that the number of registered
      * callbacks may differ from the value returned by {@link #beginBroadcast()} since
      * the former returns the number of callbacks registered at the time of the call
diff --git a/core/java/android/view/translation/ITranslationManager.aidl b/core/java/android/view/translation/ITranslationManager.aidl
index 7f6c4b4..d347f31 100644
--- a/core/java/android/view/translation/ITranslationManager.aidl
+++ b/core/java/android/view/translation/ITranslationManager.aidl
@@ -17,6 +17,7 @@
 package android.view.translation;
 
 import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.view.autofill.AutofillId;
 import android.view.translation.TranslationSpec;
 import com.android.internal.os.IResultReceiver;
@@ -40,4 +41,7 @@
     void updateUiTranslationStateByTaskId(int state, in TranslationSpec sourceSpec,
          in TranslationSpec destSpec, in List<AutofillId> viewIds, int taskId,
          int userId);
+
+    void registerUiTranslationStateCallback(in IRemoteCallback callback, int userId);
+    void unregisterUiTranslationStateCallback(in IRemoteCallback callback, int userId);
 }
diff --git a/core/java/android/view/translation/UiTranslationManager.java b/core/java/android/view/translation/UiTranslationManager.java
index 7c73e70..9fba95f 100644
--- a/core/java/android/view/translation/UiTranslationManager.java
+++ b/core/java/android/view/translation/UiTranslationManager.java
@@ -16,28 +16,36 @@
 
 package android.view.translation;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.app.assist.ActivityId;
 import android.content.Context;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IRemoteCallback;
 import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
 import android.view.View;
 import android.view.autofill.AutofillId;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
+import java.util.concurrent.Executor;
 
+// TODO(b/178044703): Describe what UI Translation is.
 /**
  * The {@link UiTranslationManager} class provides ways for apps to use the ui translation
  * function in framework.
- *
- * @hide
  */
-@SystemApi
 public final class UiTranslationManager {
 
     private static final String TAG = "UiTranslationManager";
@@ -88,6 +96,14 @@
     public @interface UiTranslationState {
     }
 
+    // Keys for the data transmitted in the internal UI Translation state callback.
+    /** @hide */
+    public static final String EXTRA_STATE = "state";
+    /** @hide */
+    public static final String EXTRA_SOURCE_LOCALE = "source_locale";
+    /** @hide */
+    public static final String EXTRA_TARGET_LOCALE = "target_locale";
+
     @NonNull
     private final Context mContext;
 
@@ -111,9 +127,12 @@
      * @param destSpec {@link TranslationSpec} for the translated data.
      * @param viewIds A list of the {@link View}'s {@link AutofillId} which needs to be translated
      * @param taskId the Activity Task id which needs ui translation
+     *
+     * @hide
      */
     // TODO, hide the APIs
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    @SystemApi
     public void startTranslation(@NonNull TranslationSpec sourceSpec,
             @NonNull TranslationSpec destSpec, @NonNull List<AutofillId> viewIds,
             int taskId) {
@@ -141,8 +160,11 @@
      * @throws IllegalArgumentException if the no {@link View}'s {@link AutofillId} in the list
      * @throws NullPointerException the sourceSpec, destSpec, viewIds, activityId or
      *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
+     *
+     * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    @SystemApi
     public void startTranslation(@NonNull TranslationSpec sourceSpec,
             @NonNull TranslationSpec destSpec, @NonNull List<AutofillId> viewIds,
             @NonNull ActivityId activityId) {
@@ -171,9 +193,12 @@
      * NOTE: Please use {@code finishTranslation(ActivityId)} instead.
      *
      * @param taskId the Activity Task id which needs ui translation
+     *
+     * @hide
      */
     // TODO, hide the APIs
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    @SystemApi
     public void finishTranslation(int taskId) {
         try {
             mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_FINISHED,
@@ -191,8 +216,11 @@
      * @param activityId the identifier for the Activity which needs ui translation
      * @throws NullPointerException the activityId or
      *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
+     *
+     * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    @SystemApi
     public void finishTranslation(@NonNull ActivityId activityId) {
         try {
             Objects.requireNonNull(activityId);
@@ -212,9 +240,12 @@
      * NOTE: Please use {@code pauseTranslation(ActivityId)} instead.
      *
      * @param taskId the Activity Task id which needs ui translation
+     *
+     * @hide
      */
     // TODO, hide the APIs
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    @SystemApi
     public void pauseTranslation(int taskId) {
         try {
             mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_PAUSED,
@@ -232,8 +263,11 @@
      * @param activityId the identifier for the Activity which needs ui translation
      * @throws NullPointerException the activityId or
      *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
+     *
+     * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    @SystemApi
     public void pauseTranslation(@NonNull ActivityId activityId) {
         try {
             Objects.requireNonNull(activityId);
@@ -253,9 +287,12 @@
      * NOTE: Please use {@code resumeTranslation(ActivityId)} instead.
      *
      * @param taskId the Activity Task id which needs ui translation
+     *
+     * @hide
      */
     // TODO, hide the APIs
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    @SystemApi
     public void resumeTranslation(int taskId) {
         try {
             mService.updateUiTranslationStateByTaskId(STATE_UI_TRANSLATION_RESUMED,
@@ -273,8 +310,11 @@
      * @param activityId the identifier for the Activity which needs ui translation
      * @throws NullPointerException the activityId or
      *         {@link android.app.assist.ActivityId#getToken()} is {@code null}
+     *
+     * @hide
      */
     @RequiresPermission(android.Manifest.permission.MANAGE_UI_TRANSLATION)
+    @SystemApi
     public void resumeTranslation(@NonNull ActivityId activityId) {
         try {
             Objects.requireNonNull(activityId);
@@ -286,4 +326,104 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    // TODO(b/178044703): Fix the View API link when it becomes public.
+    /**
+     * Register for notifications of UI Translation state changes on the foreground activity. This
+     * is available to the owning application itself and also the current input method.
+     * <p>
+     * The application whose UI is being translated can use this to customize the UI Translation
+     * behavior in ways that aren't made easy by methods like
+     * View#onCreateTranslationRequest().
+     * <p>
+     * Input methods can use this to offer complementary features to UI Translation; for example,
+     * enabling outgoing message translation when the system is translating incoming messages in a
+     * communication app.
+     *
+     * @param callback the callback to register for receiving the state change
+     *         notifications
+     */
+    public void registerUiTranslationStateCallback(
+            @NonNull @CallbackExecutor Executor executor,
+            @NonNull UiTranslationStateCallback callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        synchronized (mCallbacks) {
+            if (mCallbacks.containsKey(callback)) {
+                Log.w(TAG, "registerUiTranslationStateCallback: callback already registered;"
+                        + " ignoring.");
+                return;
+            }
+            final IRemoteCallback remoteCallback =
+                    new UiTranslationStateRemoteCallback(executor, callback);
+            try {
+                mService.registerUiTranslationStateCallback(remoteCallback, mContext.getUserId());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            mCallbacks.put(callback, remoteCallback);
+        }
+    }
+
+    /**
+     * Unregister {@code callback}.
+     *
+     * @see #registerUiTranslationStateCallback(Executor, UiTranslationStateCallback)
+     */
+    public void unregisterUiTranslationStateCallback(@NonNull UiTranslationStateCallback callback) {
+        Objects.requireNonNull(callback);
+
+        synchronized (mCallbacks) {
+            final IRemoteCallback remoteCallback = mCallbacks.get(callback);
+            if (remoteCallback == null) {
+                Log.w(TAG, "unregisterUiTranslationStateCallback: callback not found; ignoring.");
+                return;
+            }
+            try {
+                mService.unregisterUiTranslationStateCallback(remoteCallback, mContext.getUserId());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+            mCallbacks.remove(callback);
+        }
+    }
+
+    @NonNull
+    @GuardedBy("mCallbacks")
+    private final Map<UiTranslationStateCallback, IRemoteCallback> mCallbacks = new ArrayMap<>();
+
+    private static class UiTranslationStateRemoteCallback extends IRemoteCallback.Stub {
+        private final Executor mExecutor;
+        private final UiTranslationStateCallback mCallback;
+
+        UiTranslationStateRemoteCallback(Executor executor,
+                UiTranslationStateCallback callback) {
+            mExecutor = executor;
+            mCallback = callback;
+        }
+
+        @Override
+        public void sendResult(Bundle bundle) {
+            Binder.clearCallingIdentity();
+            mExecutor.execute(() -> {
+                int state = bundle.getInt(EXTRA_STATE);
+                switch (state) {
+                    case STATE_UI_TRANSLATION_STARTED:
+                    case STATE_UI_TRANSLATION_RESUMED:
+                        mCallback.onStarted(
+                                bundle.getString(EXTRA_SOURCE_LOCALE),
+                                bundle.getString(EXTRA_TARGET_LOCALE));
+                        break;
+                    case STATE_UI_TRANSLATION_PAUSED:
+                        mCallback.onPaused();
+                        break;
+                    case STATE_UI_TRANSLATION_FINISHED:
+                        mCallback.onFinished();
+                        break;
+                    default:
+                        Log.wtf(TAG, "Unexpected translation state:" + state);
+                }
+            });
+        }
+    }
 }
diff --git a/core/java/android/view/translation/UiTranslationStateCallback.java b/core/java/android/view/translation/UiTranslationStateCallback.java
new file mode 100644
index 0000000..1946b70
--- /dev/null
+++ b/core/java/android/view/translation/UiTranslationStateCallback.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.translation;
+
+import android.annotation.NonNull;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Callback for listening to UI Translation state changes. See {@link
+ * UiTranslationManager#registerUiTranslationStateCallback(Executor, UiTranslationStateCallback)}.
+ */
+public interface UiTranslationStateCallback {
+
+    /**
+     * The system is requesting translation of the UI from {@code sourceLocale} to {@code
+     * targetLocale}.
+     * <p>
+     * This is also called if either the requested {@code sourceLocale} or {@code targetLocale} has
+     * changed; or called again after {@link #onPaused()}.
+     */
+    void onStarted(@NonNull String sourceLocale, @NonNull String targetLocale);
+
+    /**
+     * The system is requesting that the application temporarily show the UI contents in their
+     * original language.
+     */
+    void onPaused();
+
+    /**
+     * The UI Translation session has ended.
+     */
+    void onFinished();
+}
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 21589c9..d02dd8c 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -4426,8 +4426,7 @@
 
     /**
      * Sets an OutlineProvider on the view whose corner radius is a dimension calculated using
-     * {@link TypedValue#applyDimension(int, float, DisplayMetrics)}. This outline may change shape
-     * during system transitions.
+     * {@link TypedValue#applyDimension(int, float, DisplayMetrics)}.
      *
      * <p>NOTE: It is recommended to use {@link TypedValue#COMPLEX_UNIT_PX} only for 0.
      * Setting margins in pixels will behave poorly when the RemoteViews object is used on a
@@ -4440,7 +4439,7 @@
 
     /**
      * Sets an OutlineProvider on the view whose corner radius is a dimension resource with
-     * {@code resId}. This outline may change shape during system transitions.
+     * {@code resId}.
      */
     public void setViewOutlinePreferredRadiusDimen(@IdRes int viewId, @DimenRes int resId) {
         addAction(new SetViewOutlinePreferredRadiusAction(viewId, resId));
diff --git a/core/proto/android/server/usagestatsservice.proto b/core/proto/android/server/usagestatsservice.proto
index e32c07f..3a959f1 100644
--- a/core/proto/android/server/usagestatsservice.proto
+++ b/core/proto/android/server/usagestatsservice.proto
@@ -57,6 +57,8 @@
     // Time attributes stored as an offset of the IntervalStats's beginTime.
     optional int64 last_time_visible_ms = 10;
     optional int64 total_time_visible_ms = 11;
+    // Time attributes stored as an offset of the IntervalStats's beginTime.
+    optional int64 last_time_component_used_ms = 12;
   }
 
   // Stores the relevant information an IntervalStats will have about a Configuration
diff --git a/core/proto/android/server/usagestatsservice_v2.proto b/core/proto/android/server/usagestatsservice_v2.proto
index 664c22d..3e5cd92 100644
--- a/core/proto/android/server/usagestatsservice_v2.proto
+++ b/core/proto/android/server/usagestatsservice_v2.proto
@@ -81,6 +81,7 @@
   optional int64 total_time_service_used_ms = 9;
   optional int64 last_time_visible_ms = 10;
   optional int64 total_time_visible_ms = 11;
+  optional int64 last_time_component_used_ms = 12;
 }
 
 /**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d783b44..f135d67 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4365,6 +4365,11 @@
     <permission android:name="android.permission.MODIFY_AUDIO_ROUTING"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @TestApi Allows an application to query audio related state.
+         @hide -->
+    <permission android:name="android.permission.QUERY_AUDIO_STATE"
+                android:protectionLevel="signature" />
+
     <!-- Allows an application to modify what effects are applied to all audio
          (matching certain criteria) from any application.
          <p>Not for use by third-party applications.</p>
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
index 8de9454..083e37a 100644
--- a/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsPersistenceTest.java
@@ -46,7 +46,8 @@
     private static final String[] USAGESTATS_PERSISTED_FIELDS = {"mBeginTimeStamp", "mEndTimeStamp",
             "mPackageName", "mPackageToken", "mLastEvent", "mAppLaunchCount", "mChooserCounts",
             "mLastTimeUsed", "mTotalTimeInForeground", "mLastTimeForegroundServiceUsed",
-            "mTotalTimeForegroundServiceUsed", "mLastTimeVisible", "mTotalTimeVisible"};
+            "mTotalTimeForegroundServiceUsed", "mLastTimeVisible", "mTotalTimeVisible",
+            "mLastTimeComponentUsed"};
     // All fields in this list are defined in UsageStats but not persisted
     private static final String[] USAGESTATS_IGNORED_FIELDS = {"CREATOR", "mActivities",
             "mForegroundServices", "mLaunchCount", "mChooserCountsObfuscated"};
diff --git a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
index 0ac00b8..858bbd2 100644
--- a/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
+++ b/core/tests/coretests/src/android/app/usage/UsageStatsTest.java
@@ -20,6 +20,7 @@
 import static android.app.usage.UsageEvents.Event.ACTIVITY_PAUSED;
 import static android.app.usage.UsageEvents.Event.ACTIVITY_RESUMED;
 import static android.app.usage.UsageEvents.Event.ACTIVITY_STOPPED;
+import static android.app.usage.UsageEvents.Event.APP_COMPONENT_USED;
 import static android.app.usage.UsageEvents.Event.CONTINUING_FOREGROUND_SERVICE;
 import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
 import static android.app.usage.UsageEvents.Event.END_OF_DAY;
@@ -137,6 +138,7 @@
         left.mPackageName = "com.test";
         left.mBeginTimeStamp = 100000;
         left.mTotalTimeInForeground = 10;
+        left.mLastTimeComponentUsed = 200000;
 
         left.mActivities.put(1, Event.ACTIVITY_RESUMED);
         left.mActivities.put(2, Event.ACTIVITY_RESUMED);
@@ -542,6 +544,19 @@
     }
 
     @Test
+    public void testEvent_APP_COMPONENT_USED() {
+        left.mPackageName = "com.test";
+        left.mBeginTimeStamp = 100000;
+        final String className = "com.test.component1";
+
+        left.update(className, 200000, APP_COMPONENT_USED, 0);
+        assertEquals(left.mLastTimeComponentUsed, 200000);
+
+        left.update(className, 300000, APP_COMPONENT_USED, 0);
+        assertEquals(left.mLastTimeComponentUsed, 300000);
+    }
+
+    @Test
     public void testEvent_DEVICE_SHUTDOWN() {
         testClosingEvent(DEVICE_SHUTDOWN);
     }
@@ -586,6 +601,7 @@
         assertEquals(us1.mBeginTimeStamp, us2.mBeginTimeStamp);
         assertEquals(us1.mLastTimeUsed, us2.mLastTimeUsed);
         assertEquals(us1.mLastTimeVisible, us2.mLastTimeVisible);
+        assertEquals(us1.mLastTimeComponentUsed, us2.mLastTimeComponentUsed);
         assertEquals(us1.mLastTimeForegroundServiceUsed, us2.mLastTimeForegroundServiceUsed);
         assertEquals(us1.mTotalTimeInForeground, us2.mTotalTimeInForeground);
         assertEquals(us1.mTotalTimeForegroundServiceUsed, us2.mTotalTimeForegroundServiceUsed);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 1770943..58bf22a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -85,7 +85,8 @@
     @Override
     public void onDisplayAdded(int displayId) {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Display added: %d", displayId);
-        final Context context = mDisplayController.getDisplayContext(displayId);
+        final Context context = mDisplayController.getDisplayContext(displayId)
+                .createWindowContext(TYPE_APPLICATION_OVERLAY, null);
         final WindowManager wm = context.getSystemService(WindowManager.class);
 
         // TODO(b/169894807): Figure out the right layer for this, needs to be below the task bar
diff --git a/media/jni/tuner/DvrClient.cpp b/media/jni/tuner/DvrClient.cpp
index 7793180..0476216 100644
--- a/media/jni/tuner/DvrClient.cpp
+++ b/media/jni/tuner/DvrClient.cpp
@@ -314,6 +314,11 @@
 }
 
 Result DvrClient::close() {
+    if (mDvrMQEventFlag != NULL) {
+        EventFlag::deleteEventFlag(&mDvrMQEventFlag);
+    }
+    mDvrMQ = NULL;
+
     if (mTunerDvr != NULL) {
         Status s = mTunerDvr->close();
         mTunerDvr = NULL;
diff --git a/media/jni/tuner/FilterClient.cpp b/media/jni/tuner/FilterClient.cpp
index f31d465..8846e4d6 100644
--- a/media/jni/tuner/FilterClient.cpp
+++ b/media/jni/tuner/FilterClient.cpp
@@ -259,6 +259,11 @@
 }
 
 Result FilterClient::close() {
+    if (mFilterMQEventFlag != NULL) {
+        EventFlag::deleteEventFlag(&mFilterMQEventFlag);
+    }
+    mFilterMQ = NULL;
+
     if (mTunerFilter != NULL) {
         Status s = mTunerFilter->close();
         closeAvSharedMemory();
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b4194fd..cf66bad 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -187,6 +187,7 @@
     <uses-permission android:name="android.permission.SET_HARMFUL_APP_WARNINGS" />
     <uses-permission android:name="android.permission.MANAGE_SENSORS" />
     <uses-permission android:name="android.permission.MANAGE_AUDIO_POLICY" />
+    <uses-permission android:name="android.permission.QUERY_AUDIO_STATE" />
     <uses-permission android:name="android.permission.MANAGE_CAMERA" />
     <!-- Permissions needed to test system only camera devices -->
     <uses-permission android:name="android.permission.CAMERA" />
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index d02ff91f..123ccee 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -324,6 +324,7 @@
 
     /** */
     @Provides
+    @SysUISingleton
     public AlwaysOnDisplayPolicy provideAlwaysOnDisplayPolicy(Context context) {
         return new AlwaysOnDisplayPolicy(context);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 97803c1..5cc0e65 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -71,7 +71,7 @@
      * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
      */
     private static boolean sEnableRemoteKeyguardAnimation =
-            SystemProperties.getBoolean(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, false);
+            SystemProperties.getBoolean(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, true);
 
     private final KeyguardViewMediator mKeyguardViewMediator;
     private final KeyguardLifecyclesDispatcher mKeyguardLifecyclesDispatcher;
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index b9d8d27..e35e987 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -195,7 +195,8 @@
         when(mFaceSensorProperties.get(anyInt())).thenReturn(new FaceSensorPropertiesInternal(
                 0 /* id */,
                 FaceSensorProperties.STRENGTH_STRONG, 1 /* maxTemplatesAllowed */,
-                false /* supportsFaceDetection */, true /* supportsSelfIllumination */));
+                false /* supportsFaceDetection */, true /* supportsSelfIllumination */,
+                false /* resetLockoutRequiresChallenge */));
 
         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
         when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 68f10a5..1950710 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -61,6 +61,8 @@
 import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.database.ContentObserver;
+import android.hardware.SensorPrivacyManager;
+import android.hardware.SensorPrivacyManagerInternal;
 import android.hardware.hdmi.HdmiAudioSystemClient;
 import android.hardware.hdmi.HdmiControlManager;
 import android.hardware.hdmi.HdmiPlaybackClient;
@@ -520,6 +522,7 @@
     /** Interface for UserManagerService. */
     private final UserManagerInternal mUserManagerInternal;
     private final ActivityManagerInternal mActivityManagerInternal;
+    private final SensorPrivacyManagerInternal mSensorPrivacyManagerInternal;
 
     private final UserRestrictionsListener mUserRestrictionsListener =
             new AudioServiceUserRestrictionsListener();
@@ -720,9 +723,12 @@
     private String mEnabledSurroundFormats;
     private boolean mSurroundModeChanged;
 
+    private boolean mSupportsMicPrivacyToggle;
+
     private boolean mMicMuteFromSwitch;
     private boolean mMicMuteFromApi;
     private boolean mMicMuteFromRestrictions;
+    private boolean mMicMuteFromPrivacyToggle;
     // caches the value returned by AudioSystem.isMicrophoneMuted()
     private boolean mMicMuteFromSystemCached;
 
@@ -822,6 +828,8 @@
 
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
+        mSensorPrivacyManagerInternal =
+                LocalServices.getService(SensorPrivacyManagerInternal.class);
 
         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
         mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
@@ -831,6 +839,9 @@
         mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
         mHasVibrator = mVibrator == null ? false : mVibrator.hasVibrator();
 
+        mSupportsMicPrivacyToggle = mContext.getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_MICROPHONE_TOGGLE);
+
         // Initialize volume
         // Priority 1 - Android Property
         // Priority 2 - Audio Policy Service
@@ -1106,6 +1117,16 @@
             }
         }
 
+        if (mSupportsMicPrivacyToggle) {
+            mSensorPrivacyManagerInternal.addSensorPrivacyListenerForAllUsers(
+                    SensorPrivacyManager.Sensors.MICROPHONE, (userId, enabled) -> {
+                        if (userId == getCurrentUserId()) {
+                            mMicMuteFromPrivacyToggle = enabled;
+                            setMicrophoneMuteNoCallerCheck(getCurrentUserId());
+                        }
+                    });
+        }
+
         mNm = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
 
         sendMsg(mAudioHandler,
@@ -3840,11 +3861,12 @@
      * @return true if microphone is reported as muted by primary HAL
      */
     public boolean isMicrophoneMuted() {
-        return mMicMuteFromSystemCached;
+        return mMicMuteFromSystemCached && !mMicMuteFromPrivacyToggle;
     }
 
     private boolean isMicrophoneSupposedToBeMuted() {
-        return mMicMuteFromSwitch || mMicMuteFromRestrictions || mMicMuteFromApi;
+        return mMicMuteFromSwitch || mMicMuteFromRestrictions || mMicMuteFromApi
+                || mMicMuteFromPrivacyToggle;
     }
 
     private void setMicrophoneMuteNoCallerCheck(int userId) {
@@ -7474,6 +7496,13 @@
                 // the current audio focus owner is no longer valid
                 mMediaFocusControl.discardAudioFocusOwner();
 
+                if (mSupportsMicPrivacyToggle) {
+                    mMicMuteFromPrivacyToggle = mSensorPrivacyManagerInternal
+                            .isSensorPrivacyEnabled(getCurrentUserId(),
+                                    SensorPrivacyManager.Sensors.MICROPHONE);
+                    setMicrophoneMuteNoCallerCheck(getCurrentUserId());
+                }
+
                 // load volume settings for new user
                 readAudioSettings(true /*userSwitch*/);
                 // preserve STREAM_MUSIC volume from one user to the next.
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 1d8f210..07a653f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -137,7 +137,7 @@
             final FaceSensorPropertiesInternal internalProp = new FaceSensorPropertiesInternal(
                     prop.commonProps.sensorId, prop.commonProps.sensorStrength,
                     prop.commonProps.maxEnrollmentsPerUser, false /* supportsFaceDetection */,
-                    prop.halControlsPreview);
+                    prop.halControlsPreview, false /* resetLockoutRequiresChallenge */);
             final Sensor sensor = new Sensor(getTag() + "/" + sensorId, this, mContext, mHandler,
                     internalProp);
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index 1b9bd7f..afe7f24 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -332,7 +332,8 @@
             @NonNull BiometricScheduler scheduler) {
         mSensorProperties = new FaceSensorPropertiesInternal(sensorId,
                 Utils.authenticatorStrengthToPropertyStrength(strength),
-                maxTemplatesAllowed, false /* supportsFaceDetect */, supportsSelfIllumination);
+                maxTemplatesAllowed, false /* supportsFaceDetect */, supportsSelfIllumination,
+                true /* resetLockoutRequiresChallenge */);
         mContext = context;
         mSensorId = sensorId;
         mScheduler = scheduler;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 6e22a79..cc3b569a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -347,7 +347,8 @@
         final @FingerprintSensorProperties.SensorType int sensorType =
                 mIsUdfps ? FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
                         : FingerprintSensorProperties.TYPE_REAR;
-        // resetLockout is controlled by the framework, so hardwareAuthToken is not required
+        // IBiometricsFingerprint@2.1 does not manage timeout below the HAL, so the Gatekeeper HAT
+        // cannot be checked
         final boolean resetLockoutRequiresHardwareAuthToken = false;
         final int maxEnrollmentsPerUser = mContext.getResources()
                 .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser);
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 06010f5..251b579 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -110,6 +110,7 @@
     private static final String ATTR_TIMESTAMP = "timestamp";
     private static final String ATTR_PACKAGE_NAME = "packageName";
     private static final String ATTR_USER = "user";
+    private static final String ATTR_UNIQUE_DISPLAY_ID = "uniqueDisplayId";
     private static final String ATTR_LUX = "lux";
     private static final String ATTR_LUX_TIMESTAMPS = "luxTimestamps";
     private static final String ATTR_BATTERY_LEVEL = "batteryLevel";
@@ -217,6 +218,9 @@
     }
 
     private void backgroundStart(float initialBrightness) {
+        if (DEBUG) {
+            Slog.d(TAG, "Background start");
+        }
         readEvents();
         readAmbientBrightnessStats();
 
@@ -311,7 +315,7 @@
      */
     public void notifyBrightnessChanged(float brightness, boolean userInitiated,
             float powerBrightnessFactor, boolean isUserSetBrightness,
-            boolean isDefaultBrightnessConfig) {
+            boolean isDefaultBrightnessConfig, String uniqueDisplayId) {
         if (DEBUG) {
             Slog.d(TAG, String.format("notifyBrightnessChanged(brightness=%f, userInitiated=%b)",
                         brightness, userInitiated));
@@ -319,13 +323,13 @@
         Message m = mBgHandler.obtainMessage(MSG_BRIGHTNESS_CHANGED,
                 userInitiated ? 1 : 0, 0 /*unused*/, new BrightnessChangeValues(brightness,
                         powerBrightnessFactor, isUserSetBrightness, isDefaultBrightnessConfig,
-                        mInjector.currentTimeMillis()));
+                        mInjector.currentTimeMillis(), uniqueDisplayId));
         m.sendToTarget();
     }
 
     private void handleBrightnessChanged(float brightness, boolean userInitiated,
             float powerBrightnessFactor, boolean isUserSetBrightness,
-            boolean isDefaultBrightnessConfig, long timestamp) {
+            boolean isDefaultBrightnessConfig, long timestamp, String uniqueDisplayId) {
         BrightnessChangeEvent.Builder builder;
 
         synchronized (mDataCollectionLock) {
@@ -350,6 +354,7 @@
             builder.setPowerBrightnessFactor(powerBrightnessFactor);
             builder.setUserBrightnessPoint(isUserSetBrightness);
             builder.setIsDefaultBrightnessConfig(isDefaultBrightnessConfig);
+            builder.setUniqueDisplayId(uniqueDisplayId);
 
             final int readingCount = mLastSensorReadings.size();
             if (readingCount == 0) {
@@ -562,6 +567,7 @@
                 out.attributeLong(null, ATTR_TIMESTAMP, toWrite[i].timeStamp);
                 out.attribute(null, ATTR_PACKAGE_NAME, toWrite[i].packageName);
                 out.attributeInt(null, ATTR_USER, userSerialNo);
+                out.attribute(null, ATTR_UNIQUE_DISPLAY_ID, toWrite[i].uniqueDisplayId);
                 out.attributeFloat(null, ATTR_BATTERY_LEVEL, toWrite[i].batteryLevel);
                 out.attributeBoolean(null, ATTR_NIGHT_MODE, toWrite[i].nightMode);
                 out.attributeInt(null, ATTR_COLOR_TEMPERATURE,
@@ -646,6 +652,8 @@
                     builder.setPackageName(parser.getAttributeValue(null, ATTR_PACKAGE_NAME));
                     builder.setUserId(mInjector.getUserId(mUserManager,
                             parser.getAttributeInt(null, ATTR_USER)));
+                    builder.setUniqueDisplayId(
+                            parser.getAttributeValue(null, ATTR_UNIQUE_DISPLAY_ID));
                     builder.setBatteryLevel(parser.getAttributeFloat(null, ATTR_BATTERY_LEVEL));
                     builder.setNightMode(parser.getAttributeBoolean(null, ATTR_NIGHT_MODE));
                     builder.setColorTemperature(
@@ -980,7 +988,8 @@
                     boolean userInitiatedChange = (msg.arg1 == 1);
                     handleBrightnessChanged(values.brightness, userInitiatedChange,
                             values.powerBrightnessFactor, values.isUserSetBrightness,
-                            values.isDefaultBrightnessConfig, values.timestamp);
+                            values.isDefaultBrightnessConfig, values.timestamp,
+                            values.uniqueDisplayId);
                     break;
                 case MSG_START_SENSOR_LISTENER:
                     startSensorListener();
@@ -1007,20 +1016,22 @@
     }
 
     private static class BrightnessChangeValues {
-        final float brightness;
-        final float powerBrightnessFactor;
-        final boolean isUserSetBrightness;
-        final boolean isDefaultBrightnessConfig;
-        final long timestamp;
+        public final float brightness;
+        public final float powerBrightnessFactor;
+        public final boolean isUserSetBrightness;
+        public final boolean isDefaultBrightnessConfig;
+        public final long timestamp;
+        public final String uniqueDisplayId;
 
         BrightnessChangeValues(float brightness, float powerBrightnessFactor,
                 boolean isUserSetBrightness, boolean isDefaultBrightnessConfig,
-                long timestamp) {
+                long timestamp, String uniqueDisplayId) {
             this.brightness = brightness;
             this.powerBrightnessFactor = powerBrightnessFactor;
             this.isUserSetBrightness = isUserSetBrightness;
             this.isDefaultBrightnessConfig = isDefaultBrightnessConfig;
             this.timestamp = timestamp;
+            this.uniqueDisplayId = uniqueDisplayId;
         }
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 96a7416..82ca820 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -376,6 +376,8 @@
     private final ColorSpace mWideColorSpace;
 
     private SensorManager mSensorManager;
+    private BrightnessTracker mBrightnessTracker;
+
 
     // Whether minimal post processing is allowed by the user.
     @GuardedBy("mSyncRoot")
@@ -1162,7 +1164,7 @@
 
         DisplayPowerController dpc = mDisplayPowerControllers.get(displayId);
         if (dpc != null) {
-            dpc.onDisplayChanged();
+            dpc.onDisplayChangedLocked();
         }
     }
 
@@ -1851,7 +1853,10 @@
             for (int i = 0; i < displayPowerControllerCount; i++) {
                 mDisplayPowerControllers.valueAt(i).dump(pw);
             }
-
+            if (mBrightnessTracker != null) {
+                pw.println();
+                mBrightnessTracker.dump(pw);
+            }
             pw.println();
             mPersistentDataStore.dump(pw);
         }
@@ -1937,9 +1942,12 @@
             // initPowerManagement has not yet been called.
             return;
         }
+        if (mBrightnessTracker == null) {
+            mBrightnessTracker = new BrightnessTracker(mContext, null);
+        }
         final DisplayPowerController displayPowerController = new DisplayPowerController(
                 mContext, mDisplayPowerCallbacks, mPowerHandler, mSensorManager,
-                mDisplayBlanker, display);
+                mDisplayBlanker, display, mBrightnessTracker);
         mDisplayPowerControllers.append(display.getDisplayIdLocked(), displayPowerController);
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index e44ecac..7110d3e 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -174,6 +174,9 @@
     // The ID of the LogicalDisplay tied to this DisplayPowerController.
     private final int mDisplayId;
 
+    // The unique ID of the primary display device currently tied to this logical display
+    private String mUniqueDisplayId;
+
     // Tracker for brightness changes.
     @Nullable
     private final BrightnessTracker mBrightnessTracker;
@@ -416,16 +419,15 @@
      */
     public DisplayPowerController(Context context,
             DisplayPowerCallbacks callbacks, Handler handler,
-            SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay) {
+            SensorManager sensorManager, DisplayBlanker blanker, LogicalDisplay logicalDisplay,
+            BrightnessTracker brightnessTracker) {
         mLogicalDisplay = logicalDisplay;
         mDisplayId = mLogicalDisplay.getDisplayIdLocked();
         mHandler = new DisplayControllerHandler(handler.getLooper());
 
         if (mDisplayId == Display.DEFAULT_DISPLAY) {
-            mBrightnessTracker = new BrightnessTracker(context, null);
             mBatteryStats = BatteryStatsService.getService();
         } else {
-            mBrightnessTracker = null;
             mBatteryStats = null;
         }
 
@@ -435,6 +437,7 @@
         mWindowManagerPolicy = LocalServices.getService(WindowManagerPolicy.class);
         mBlanker = blanker;
         mContext = context;
+        mBrightnessTracker = brightnessTracker;
 
 
         PowerManager pm = context.getSystemService(PowerManager.class);
@@ -756,8 +759,10 @@
      * when displays get swapped on foldable devices.  For example, different brightness properties
      * of each display need to be properly reflected in AutomaticBrightnessController.
      */
-    public void onDisplayChanged() {
+    public void onDisplayChangedLocked() {
         // TODO: b/175821789 - Support high brightness on multiple (folding) displays
+
+        mUniqueDisplayId = mLogicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
     }
 
     /**
@@ -780,10 +785,6 @@
                 mAutomaticBrightnessController.stop();
             }
 
-            if (mBrightnessTracker != null) {
-                mBrightnessTracker.stop();
-            }
-
             mContext.getContentResolver().unregisterContentObserver(mSettingsObserver);
         }
     }
@@ -1899,7 +1900,7 @@
                     : 1.0f;
             mBrightnessTracker.notifyBrightnessChanged(brightnessInNits, userInitiated,
                     powerFactor, hadUserDataPoint,
-                    mAutomaticBrightnessController.isDefaultConfig());
+                    mAutomaticBrightnessController.isDefaultConfig(), mUniqueDisplayId);
         }
     }
 
@@ -2067,11 +2068,6 @@
             mAutomaticBrightnessController.dump(pw);
         }
 
-        if (mBrightnessTracker != null) {
-            pw.println();
-            mBrightnessTracker.dump(pw);
-        }
-
         pw.println();
         if (mDisplayWhiteBalanceController != null) {
             mDisplayWhiteBalanceController.dump(pw);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index aaec89a..2546118 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -853,14 +853,6 @@
             // Do not lock when calling these SurfaceControl methods because they are sync
             // operations that may block for a while when setting display power mode.
             mSurfaceControlProxy.setDesiredDisplayModeSpecs(displayToken, modeSpecs);
-
-            final int sfActiveModeId = mSurfaceControlProxy
-                    .getDynamicDisplayInfo(displayToken).activeDisplayModeId;
-            synchronized (getSyncRoot()) {
-                if (updateActiveModeLocked(sfActiveModeId)) {
-                    updateDeviceInfoLocked();
-                }
-            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index e6e2f96..03a8338 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -431,6 +431,13 @@
 
     private final SelectRequestBuffer mSelectRequestBuffer = new SelectRequestBuffer();
 
+    @VisibleForTesting HdmiControlService(Context context, List<Integer> deviceTypes) {
+        super(context);
+        mLocalDevices = deviceTypes;
+        mSettingsObserver = new SettingsObserver(mHandler);
+        mHdmiCecConfig = new HdmiCecConfig(context);
+    }
+
     public HdmiControlService(Context context) {
         super(context);
         List<Integer> deviceTypes = HdmiProperties.device_type();
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index db3d7ad..89dac05 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -664,13 +664,16 @@
     // naturally.
     private boolean mInSizeCompatModeForBounds = false;
 
-    // Whether this activity is letterboxed for fixed orientation. If letterboxed due to fixed
-    // orientation then aspect ratio restrictions are also already respected.
+    // Bounds populated in resolveFixedOrientationConfiguration when this activity is letterboxed
+    // for fixed orientation. If not null, they are used as parent container in
+    // resolveSizeCompatModeConfiguration and in a constructor of CompatDisplayInsets. If
+    // letterboxed due to fixed orientation then aspect ratio restrictions are also respected.
     // This happens when an activity has fixed orientation which doesn't match orientation of the
     // parent because a display is ignoring orientation request or fixed to user rotation.
     // See WindowManagerService#getIgnoreOrientationRequest and
     // WindowManagerService#getFixedToUserRotation for more context.
-    private boolean mIsLetterboxedForFixedOrientationAndAspectRatio = false;
+    @Nullable
+    private Rect mLetterboxBoundsForFixedOrientationAndAspectRatio;
 
     // activity is not displayed?
     // TODO: rename to mNoDisplay
@@ -6863,7 +6866,7 @@
     }
 
     // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
-    private void updateCompatDisplayInsets(@Nullable Rect fixedOrientationBounds) {
+    private void updateCompatDisplayInsets() {
         if (mCompatDisplayInsets != null || !shouldCreateCompatDisplayInsets()) {
             // The override configuration is set only once in size compatibility mode.
             return;
@@ -6891,7 +6894,8 @@
 
         // The role of CompatDisplayInsets is like the override bounds.
         mCompatDisplayInsets =
-                new CompatDisplayInsets(mDisplayContent, this, fixedOrientationBounds);
+                new CompatDisplayInsets(
+                        mDisplayContent, this, mLetterboxBoundsForFixedOrientationAndAspectRatio);
     }
 
     @VisibleForTesting
@@ -6945,8 +6949,6 @@
                 || windowingMode == WINDOWING_MODE_FULLSCREEN) {
             resolveFixedOrientationConfiguration(newParentConfiguration);
         }
-        final Rect fixedOrientationBounds = isLetterboxedForFixedOrientationAndAspectRatio()
-                ? new Rect(resolvedConfig.windowConfiguration.getBounds()) : null;
 
         if (mCompatDisplayInsets != null) {
             resolveSizeCompatModeConfiguration(newParentConfiguration);
@@ -6966,7 +6968,7 @@
         }
 
         if (mVisibleRequested) {
-            updateCompatDisplayInsets(fixedOrientationBounds);
+            updateCompatDisplayInsets();
         }
 
         // TODO(b/175212232): Consolidate position logic from each "resolve" method above here.
@@ -7001,7 +7003,7 @@
      * WindowManagerService#getIgnoreOrientationRequest} for more context.
      */
     boolean isLetterboxedForFixedOrientationAndAspectRatio() {
-        return mIsLetterboxedForFixedOrientationAndAspectRatio;
+        return mLetterboxBoundsForFixedOrientationAndAspectRatio != null;
     }
 
     /**
@@ -7012,7 +7014,7 @@
      * in this methiod.
      */
     private void resolveFixedOrientationConfiguration(@NonNull Configuration newParentConfig) {
-        mIsLetterboxedForFixedOrientationAndAspectRatio = false;
+        mLetterboxBoundsForFixedOrientationAndAspectRatio = null;
         if (handlesOrientationChangeFromDescendant()) {
             // No need to letterbox because of fixed orientation. Display will handle
             // fixed-orientation requests.
@@ -7089,7 +7091,7 @@
         // Calculate app bounds using fixed orientation bounds because they will be needed later
         // for comparison with size compat app bounds in {@link resolveSizeCompatModeConfiguration}.
         task.computeConfigResourceOverrides(getResolvedOverrideConfiguration(), newParentConfig);
-        mIsLetterboxedForFixedOrientationAndAspectRatio = true;
+        mLetterboxBoundsForFixedOrientationAndAspectRatio = new Rect(resolvedBounds);
     }
 
     /**
@@ -7635,6 +7637,12 @@
         if (getConfiguration().equals(mTmpConfig) && !forceNewConfig && !displayChanged) {
             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Configuration & display "
                     + "unchanged in %s", this);
+            // It's possible that resolveOverrideConfiguration was called before mVisibleRequested
+            // became true and mCompatDisplayInsets may not have been created so ensure
+            // that mCompatDisplayInsets is created here.
+            if (mVisibleRequested) {
+                updateCompatDisplayInsets();
+            }
             return true;
         }
 
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 01f0359..d929d50 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -448,7 +448,8 @@
 
         final Looper looper = UiThread.getHandler().getLooper();
         mHandler = new PolicyHandler(looper);
-        mSystemGestures = new SystemGesturesPointerEventListener(mContext, mHandler,
+        // TODO(b/181821798) Migrate SystemGesturesPointerEventListener to use window context.
+        mSystemGestures = new SystemGesturesPointerEventListener(mUiContext, mHandler,
                 new SystemGesturesPointerEventListener.Callbacks() {
                     @Override
                     public void onSwipeFromTop() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ec012fc3..73b0555 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -431,7 +431,7 @@
      * @see #ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY
      */
     public static boolean sEnableRemoteKeyguardAnimation =
-            SystemProperties.getBoolean(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, false);
+            SystemProperties.getBoolean(ENABLE_REMOTE_KEYGUARD_ANIMATION_PROPERTY, true);
 
     private static final String DISABLE_TRIPLE_BUFFERING_PROPERTY =
             "ro.sf.disable_triple_buffer";
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ac2281a..ffae3ab 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -14699,24 +14699,25 @@
 
     private void sendNetworkLoggingNotificationLocked() {
         ensureLocked();
-        final ActiveAdmin activeAdmin = getNetworkLoggingControllingAdminLocked();
-        if (activeAdmin == null || !activeAdmin.isNetworkLoggingEnabled) {
+        // Send a network logging notification if the admin is a device owner, not profile owner.
+        final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+        if (deviceOwner == null || !deviceOwner.isNetworkLoggingEnabled) {
             return;
         }
-        if (activeAdmin.numNetworkLoggingNotifications
+        if (deviceOwner.numNetworkLoggingNotifications
                 >= ActiveAdmin.DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN) {
             return;
         }
         final long now = System.currentTimeMillis();
-        if (now - activeAdmin.lastNetworkLoggingNotificationTimeMs < MS_PER_DAY) {
+        if (now - deviceOwner.lastNetworkLoggingNotificationTimeMs < MS_PER_DAY) {
             return;
         }
-        activeAdmin.numNetworkLoggingNotifications++;
-        if (activeAdmin.numNetworkLoggingNotifications
+        deviceOwner.numNetworkLoggingNotifications++;
+        if (deviceOwner.numNetworkLoggingNotifications
                 >= ActiveAdmin.DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN) {
-            activeAdmin.lastNetworkLoggingNotificationTimeMs = 0;
+            deviceOwner.lastNetworkLoggingNotificationTimeMs = 0;
         } else {
-            activeAdmin.lastNetworkLoggingNotificationTimeMs = now;
+            deviceOwner.lastNetworkLoggingNotificationTimeMs = now;
         }
         final PackageManagerInternal pm = mInjector.getPackageManagerInternal();
         final Intent intent = new Intent(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
@@ -14736,7 +14737,7 @@
                         .bigText(mContext.getString(R.string.network_logging_notification_text)))
                 .build();
         mInjector.getNotificationManager().notify(SystemMessage.NOTE_NETWORK_LOGGING, notification);
-        saveSettingsLocked(activeAdmin.getUserHandle().getIdentifier());
+        saveSettingsLocked(deviceOwner.getUserHandle().getIdentifier());
     }
 
     /**
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index c38d0b3..e3fbedd 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -86,6 +86,9 @@
     static constexpr auto maxBindDelay = 10000s;
     static constexpr auto bindDelayMultiplier = 10;
     static constexpr auto bindDelayJitterDivider = 10;
+
+    // Max interval after system invoked the DL when readlog collection can be enabled.
+    static constexpr auto readLogsMaxInterval = 2h;
 };
 
 static const Constants& constants() {
@@ -290,6 +293,14 @@
     ::rmdir(path::c_str(root));
 }
 
+void IncrementalService::IncFsMount::setReadLogsEnabled(bool value) {
+    if (value) {
+        flags |= StorageFlags::ReadLogsEnabled;
+    } else {
+        flags &= ~StorageFlags::ReadLogsEnabled;
+    }
+}
+
 IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir)
       : mVold(sm.getVoldService()),
         mDataLoaderManager(sm.getDataLoaderManager()),
@@ -406,7 +417,7 @@
 }
 
 bool IncrementalService::needStartDataLoaderLocked(IncFsMount& ifs) {
-    if (ifs.dataLoaderStub->params().packageName == Constants::systemPackage) {
+    if (ifs.dataLoaderStub->isSystemDataLoader()) {
         return true;
     }
 
@@ -658,7 +669,7 @@
     return storageId;
 }
 
-bool IncrementalService::startLoading(StorageId storage,
+bool IncrementalService::startLoading(StorageId storageId,
                                       content::pm::DataLoaderParamsParcel&& dataLoaderParams,
                                       const DataLoaderStatusListener& statusListener,
                                       StorageHealthCheckParams&& healthCheckParams,
@@ -666,12 +677,12 @@
                                       const std::vector<PerUidReadTimeouts>& perUidReadTimeouts) {
     // Per Uid timeouts.
     if (!perUidReadTimeouts.empty()) {
-        setUidReadTimeouts(storage, perUidReadTimeouts);
+        setUidReadTimeouts(storageId, perUidReadTimeouts);
     }
 
     // Re-initialize DataLoader.
     std::unique_lock l(mLock);
-    const auto ifs = getIfsLocked(storage);
+    const auto ifs = getIfsLocked(storageId);
     if (!ifs) {
         return false;
     }
@@ -686,6 +697,32 @@
                                             std::move(healthCheckParams), &healthListener);
     CHECK(dataLoaderStub);
 
+    if (dataLoaderStub->isSystemDataLoader()) {
+        // Readlogs from system dataloader (adb) can always be collected.
+        ifs->startLoadingTs = TimePoint::max();
+    } else {
+        // Assign time when installation wants the DL to start streaming.
+        const auto startLoadingTs = mClock->now();
+        ifs->startLoadingTs = startLoadingTs;
+        // Setup a callback to disable the readlogs after max interval.
+        addTimedJob(*mTimedQueue, storageId, Constants::readLogsMaxInterval,
+                    [this, storageId, startLoadingTs]() {
+                        const auto ifs = getIfs(storageId);
+                        if (!ifs) {
+                            LOG(WARNING) << "Can't disable the readlogs, invalid storageId: "
+                                         << storageId;
+                            return;
+                        }
+                        if (ifs->startLoadingTs != startLoadingTs) {
+                            LOG(INFO) << "Can't disable the readlogs, timestamp mismatch (new "
+                                         "installation?): "
+                                      << storageId;
+                            return;
+                        }
+                        setStorageParams(*ifs, storageId, /*enableReadLogs=*/false);
+                    });
+    }
+
     return dataLoaderStub->requestStart();
 }
 
@@ -735,11 +772,16 @@
         LOG(ERROR) << "setStorageParams failed, invalid storageId: " << storageId;
         return -EINVAL;
     }
+    return setStorageParams(*ifs, storageId, enableReadLogs);
+}
 
-    const auto& params = ifs->dataLoaderStub->params();
+int IncrementalService::setStorageParams(IncFsMount& ifs, StorageId storageId,
+                                         bool enableReadLogs) {
+    const auto& params = ifs.dataLoaderStub->params();
     if (enableReadLogs) {
-        if (!ifs->readLogsAllowed()) {
-            LOG(ERROR) << "setStorageParams failed, readlogs disabled for storageId: " << storageId;
+        if (!ifs.readLogsAllowed()) {
+            LOG(ERROR) << "setStorageParams failed, readlogs disallowed for storageId: "
+                       << storageId;
             return -EPERM;
         }
 
@@ -760,9 +802,19 @@
                        << " check failed: " << status.toString8();
             return fromBinderStatus(status);
         }
+
+        // Check installation time.
+        const auto now = mClock->now();
+        const auto startLoadingTs = ifs.startLoadingTs;
+        if (startLoadingTs <= now && now - startLoadingTs > Constants::readLogsMaxInterval) {
+            LOG(ERROR) << "setStorageParams failed, readlogs can't be enabled at this time, "
+                          "storageId: "
+                       << storageId;
+            return -EPERM;
+        }
     }
 
-    if (auto status = applyStorageParams(*ifs, enableReadLogs); !status.isOk()) {
+    if (auto status = applyStorageParams(ifs, enableReadLogs); !status.isOk()) {
         LOG(ERROR) << "applyStorageParams failed: " << status.toString8();
         return fromBinderStatus(status);
     }
@@ -2222,6 +2274,10 @@
     return dataloader;
 }
 
+bool IncrementalService::DataLoaderStub::isSystemDataLoader() const {
+    return (params().packageName == Constants::systemPackage);
+}
+
 bool IncrementalService::DataLoaderStub::requestCreate() {
     return setTargetStatus(IDataLoaderStatusListener::DATA_LOADER_CREATED);
 }
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index 4eb5138..bc441c7 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -231,6 +231,7 @@
 
         MountId id() const { return mId.load(std::memory_order_relaxed); }
         const content::pm::DataLoaderParamsParcel& params() const { return mParams; }
+        bool isSystemDataLoader() const;
         void setHealthListener(StorageHealthCheckParams&& healthCheckParams,
                                const StorageHealthListener* healthListener);
         long elapsedMsSinceOldestPendingRead();
@@ -330,6 +331,7 @@
         StorageMap storages;
         BindMap bindPoints;
         DataLoaderStubPtr dataLoaderStub;
+        TimePoint startLoadingTs = {};
         std::atomic<int> nextStorageDirNo{0};
         const IncrementalService& incrementalService;
 
@@ -348,12 +350,7 @@
         void disallowReadLogs() { flags &= ~StorageFlags::ReadLogsAllowed; }
         int32_t readLogsAllowed() const { return (flags & StorageFlags::ReadLogsAllowed); }
 
-        void setReadLogsEnabled(bool value) {
-            if (value)
-                flags |= StorageFlags::ReadLogsEnabled;
-            else
-                flags &= ~StorageFlags::ReadLogsEnabled;
-        }
+        void setReadLogsEnabled(bool value);
         int32_t readLogsEnabled() const { return (flags & StorageFlags::ReadLogsEnabled); }
 
         static void cleanupFilesystem(std::string_view root);
@@ -411,6 +408,8 @@
                                              IncFsMount::StorageMap::const_iterator storageIt,
                                              std::string_view path) const;
     int makeDirs(const IncFsMount& ifs, StorageId storageId, std::string_view path, int mode);
+
+    int setStorageParams(IncFsMount& ifs, StorageId storageId, bool enableReadLogs);
     binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);
 
     int isFileFullyLoadedFromPath(const IncFsMount& ifs, std::string_view filePath) const;
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 25b34b56..bf798273 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -908,7 +908,7 @@
     EXPECT_CALL(*mDataLoader, start(_)).Times(6);
     EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
-    EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(2);
+    EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(3);
     TemporaryDir tempDir;
     int storageId =
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
@@ -1119,7 +1119,7 @@
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     EXPECT_CALL(*mLooper, addFd(MockIncFs::kPendingReadsFd, _, _, _, _)).Times(2);
     EXPECT_CALL(*mLooper, removeFd(MockIncFs::kPendingReadsFd)).Times(2);
-    EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(4);
+    EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(5);
 
     sp<NiceMock<MockStorageHealthListener>> listener{new NiceMock<MockStorageHealthListener>};
     NiceMock<MockStorageHealthListener>* listenerMock = listener.get();
@@ -1292,6 +1292,147 @@
     ASSERT_EQ(mDataLoader->setStorageParams(true), -EPERM);
 }
 
+TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndTimedOut) {
+    mVold->setIncFsMountOptionsSuccess();
+    mAppOpsManager->checkPermissionSuccess();
+
+    const auto readLogsMaxInterval = 2h;
+
+    EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
+    EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+    // Enabling and then disabling readlogs.
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(2);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+    // After setIncFsMountOptions succeeded expecting to start watching.
+    EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
+    // Not expecting callback removal.
+    EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
+    EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(1);
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_GE(storageId, 0);
+    ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+                                                  {}, {}));
+
+    // Disable readlogs callback present.
+    ASSERT_EQ(storageId, mTimedQueue->mId);
+    ASSERT_EQ(mTimedQueue->mAfter, readLogsMaxInterval);
+    auto callback = mTimedQueue->mWhat;
+    mTimedQueue->clearJob(storageId);
+
+    ASSERT_GE(mDataLoader->setStorageParams(true), 0);
+    // Now advance clock for 1hr.
+    mClock->advance(1h);
+    ASSERT_GE(mDataLoader->setStorageParams(true), 0);
+    // Now call the timed callback, it should turn off the readlogs.
+    callback();
+    // Now advance clock for 2hrs.
+    mClock->advance(readLogsMaxInterval);
+    ASSERT_EQ(mDataLoader->setStorageParams(true), -EPERM);
+}
+
+TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndNoTimedOutForSystem) {
+    mVold->setIncFsMountOptionsSuccess();
+    mAppOpsManager->checkPermissionSuccess();
+
+    const auto readLogsMaxInterval = 2h;
+
+    EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_));
+    EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+    // Enabling and then disabling readlogs.
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(3);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(0);
+    // After setIncFsMountOptions succeeded expecting to start watching.
+    EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
+    // Not expecting callback removal.
+    EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
+    EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(0);
+    // System data loader.
+    mDataLoaderParcel.packageName = "android";
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_GE(storageId, 0);
+    ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+                                                  {}, {}));
+
+    // No readlogs callback.
+    ASSERT_EQ(mTimedQueue->mAfter, 0ms);
+    ASSERT_EQ(mTimedQueue->mWhat, nullptr);
+
+    ASSERT_GE(mDataLoader->setStorageParams(true), 0);
+    // Now advance clock for 1hr.
+    mClock->advance(1h);
+    ASSERT_GE(mDataLoader->setStorageParams(true), 0);
+    // Now advance clock for 2hrs.
+    mClock->advance(readLogsMaxInterval);
+    ASSERT_EQ(mDataLoader->setStorageParams(true), 0);
+}
+
+TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndNewInstall) {
+    mVold->setIncFsMountOptionsSuccess();
+    mAppOpsManager->checkPermissionSuccess();
+
+    const auto readLogsMaxInterval = 2h;
+
+    EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(2);
+    EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+    // Enabling and then disabling readlogs.
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(3);
+    EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+    // After setIncFsMountOptions succeeded expecting to start watching.
+    EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
+    // Not expecting callback removal.
+    EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
+    EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(2);
+    TemporaryDir tempDir;
+    int storageId =
+            mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
+                                               IncrementalService::CreateOptions::CreateNew);
+    ASSERT_GE(storageId, 0);
+
+    auto dataLoaderParcel = mDataLoaderParcel;
+    ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(dataLoaderParcel), {}, {},
+                                                  {}, {}));
+
+    // Disable readlogs callback present.
+    ASSERT_EQ(storageId, mTimedQueue->mId);
+    ASSERT_EQ(mTimedQueue->mAfter, readLogsMaxInterval);
+    auto callback = mTimedQueue->mWhat;
+    mTimedQueue->clearJob(storageId);
+
+    ASSERT_GE(mDataLoader->setStorageParams(true), 0);
+    // Now advance clock for 1.5hrs.
+    mClock->advance(90min);
+    ASSERT_GE(mDataLoader->setStorageParams(true), 0);
+
+    // New installation.
+    ASSERT_TRUE(mIncrementalService->startLoading(storageId, std::move(mDataLoaderParcel), {}, {},
+                                                  {}, {}));
+
+    // New callback present.
+    ASSERT_EQ(storageId, mTimedQueue->mId);
+    ASSERT_EQ(mTimedQueue->mAfter, readLogsMaxInterval);
+    auto callback2 = mTimedQueue->mWhat;
+    mTimedQueue->clearJob(storageId);
+
+    // Old callback should not disable readlogs (setIncFsMountOptions should be called only once).
+    callback();
+    // Advance clock for another 1.5hrs.
+    mClock->advance(90min);
+    // Still success even it's 3hrs past first install.
+    ASSERT_GE(mDataLoader->setStorageParams(true), 0);
+
+    // New one should disable.
+    callback2();
+    // And timeout.
+    mClock->advance(90min);
+    ASSERT_EQ(mDataLoader->setStorageParams(true), -EPERM);
+}
+
 TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) {
     mVold->setIncFsMountOptionsSuccess();
     mAppOpsManager->checkPermissionSuccess();
@@ -1675,7 +1816,7 @@
     EXPECT_CALL(*mDataLoader, start(_)).Times(1);
     EXPECT_CALL(*mDataLoader, destroy(_)).Times(1);
     EXPECT_CALL(*mIncFs, setUidReadTimeouts(_, _)).Times(0);
-    EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(0);
+    EXPECT_CALL(*mTimedQueue, addJob(_, _, _)).Times(1);
     EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
     TemporaryDir tempDir;
     int storageId =
@@ -1702,6 +1843,9 @@
     // Empty storage.
     mIncFs->countFilledBlocksEmpty();
 
+    // Mark DataLoader as 'system' so that readlogs don't pollute the timed queue.
+    mDataLoaderParcel.packageName = "android";
+
     TemporaryDir tempDir;
     int storageId =
             mIncrementalService->createStorage(tempDir.path, mDataLoaderParcel,
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index 893ce9e..bdf94f3 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -81,6 +81,7 @@
 public class BrightnessTrackerTest {
     private static final float DEFAULT_INITIAL_BRIGHTNESS = 2.5f;
     private static final boolean DEFAULT_COLOR_SAMPLING_ENABLED = true;
+    private static final String DEFAULT_DISPLAY_ID = "123";
     private static final float FLOAT_DELTA = 0.01f;
 
     private BrightnessTracker mTracker;
@@ -285,18 +286,20 @@
 
     @Test
     public void testBrightnessEvent() {
-        final int brightness = 20;
+        final float brightness = 0.5f;
+        final String displayId = "1234";
 
         startTracker(mTracker);
         mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
         mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2));
-        notifyBrightnessChanged(mTracker, brightness);
+        notifyBrightnessChanged(mTracker, brightness, displayId);
         List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
         mTracker.stop();
 
         assertEquals(1, events.size());
         BrightnessChangeEvent event = events.get(0);
         assertEquals(mInjector.currentTimeMillis(), event.timeStamp);
+        assertEquals(displayId, event.uniqueDisplayId);
         assertEquals(1, event.luxValues.length);
         assertEquals(1.0f, event.luxValues[0], FLOAT_DELTA);
         assertEquals(mInjector.currentTimeMillis() - TimeUnit.SECONDS.toMillis(2),
@@ -314,6 +317,7 @@
     public void testBrightnessFullPopulatedEvent() {
         final int initialBrightness = 230;
         final int brightness = 130;
+        final String displayId = "1234";
 
         mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1);
         mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 3333);
@@ -326,7 +330,7 @@
                 batteryChangeEvent(30, 60));
         mInjector.mSensorListener.onSensorChanged(createSensorEvent(1000.0f));
         final long sensorTime = mInjector.currentTimeMillis();
-        notifyBrightnessChanged(mTracker, brightness);
+        notifyBrightnessChanged(mTracker, brightness, displayId);
         List<BrightnessChangeEvent> eventsNoPackage
                 = mTracker.getEvents(0, false).getList();
         List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
@@ -335,6 +339,7 @@
         assertEquals(1, events.size());
         BrightnessChangeEvent event = events.get(0);
         assertEquals(event.timeStamp, mInjector.currentTimeMillis());
+        assertEquals(displayId, event.uniqueDisplayId);
         assertArrayEquals(new float[] {1000.0f}, event.luxValues, 0.01f);
         assertArrayEquals(new long[] {sensorTime}, event.luxTimestamps);
         assertEquals(brightness, event.brightness, FLOAT_DELTA);
@@ -364,7 +369,7 @@
         final int systemUpdatedBrightness = 20;
         notifyBrightnessChanged(mTracker, systemUpdatedBrightness, false /*userInitiated*/,
                 0.5f /*powerBrightnessFactor(*/, false /*isUserSetBrightness*/,
-                false /*isDefaultBrightnessConfig*/);
+                false /*isDefaultBrightnessConfig*/, DEFAULT_DISPLAY_ID);
         List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
         // No events because we filtered out our change.
         assertEquals(0, events.size());
@@ -455,6 +460,7 @@
                 + "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\" "
                 + "reduceBrightColors=\"false\" reduceBrightColorsStrength=\"40\" "
                 + "reduceBrightColorsOffset=\"0\"\n"
+                + "uniqueDisplayId=\"123\""
                 + "lux=\"32.2,31.1\" luxTimestamps=\""
                 + Long.toString(someTimeAgo) + "," + Long.toString(someTimeAgo) + "\""
                 + "defaultConfig=\"true\" powerSaveFactor=\"0.5\" userPoint=\"true\" />"
@@ -465,6 +471,7 @@
                 + "batteryLevel=\"0.5\" nightMode=\"true\" colorTemperature=\"3235\" "
                 + "reduceBrightColors=\"true\" reduceBrightColorsStrength=\"40\" "
                 + "reduceBrightColorsOffset=\"0\"\n"
+                + "uniqueDisplayId=\"456\""
                 + "lux=\"132.2,131.1\" luxTimestamps=\""
                 + Long.toString(someTimeAgo) + "," + Long.toString(someTimeAgo) + "\""
                 + "colorSampleDuration=\"3456\" colorValueBuckets=\"123,598,23,19\"/>"
@@ -476,6 +483,7 @@
                 + "batteryLevel=\"1.0\" nightMode=\"false\" colorTemperature=\"0\" "
                 + "reduceBrightColors=\"false\" reduceBrightColorsStrength=\"40\" "
                 + "reduceBrightColorsOffset=\"0\"\n"
+                + "uniqueDisplayId=\"789\""
                 + "lux=\"32.2,31.1\" luxTimestamps=\""
                 + Long.toString(twoMonthsAgo) + "," + Long.toString(twoMonthsAgo) + "\"/>"
                 + "</events>";
@@ -485,6 +493,7 @@
         BrightnessChangeEvent event = events.get(0);
         assertEquals(someTimeAgo, event.timeStamp);
         assertEquals(194.2, event.brightness, FLOAT_DELTA);
+        assertEquals("123", event.uniqueDisplayId);
         assertArrayEquals(new float[] {32.2f, 31.1f}, event.luxValues, FLOAT_DELTA);
         assertArrayEquals(new long[] {someTimeAgo, someTimeAgo}, event.luxTimestamps);
         assertEquals(32.333, event.lastBrightness, FLOAT_DELTA);
@@ -503,6 +512,7 @@
         event = events.get(0);
         assertEquals(someTimeAgo, event.timeStamp);
         assertEquals(71, event.brightness, FLOAT_DELTA);
+        assertEquals("456", event.uniqueDisplayId);
         assertArrayEquals(new float[] {132.2f, 131.1f}, event.luxValues, FLOAT_DELTA);
         assertArrayEquals(new long[] {someTimeAgo, someTimeAgo}, event.luxTimestamps);
         assertEquals(32, event.lastBrightness, FLOAT_DELTA);
@@ -575,6 +585,7 @@
     @Test
     public void testWriteThenRead() throws Exception {
         final int brightness = 20;
+        final String displayId = "1234";
 
         mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1);
         mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 3339);
@@ -593,7 +604,7 @@
         mInjector.incrementTime(TimeUnit.SECONDS.toMillis(3));
         notifyBrightnessChanged(mTracker, brightness, true /*userInitiated*/,
                 0.5f /*powerBrightnessFactor*/, true /*hasUserBrightnessPoints*/,
-                false /*isDefaultBrightnessConfig*/);
+                false /*isDefaultBrightnessConfig*/, displayId);
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         mTracker.writeEventsLocked(baos);
         mTracker.stop();
@@ -607,6 +618,7 @@
 
         assertEquals(1, events.size());
         BrightnessChangeEvent event = events.get(0);
+        assertEquals(displayId, event.uniqueDisplayId);
         assertArrayEquals(new float[] {2000.0f, 3000.0f}, event.luxValues, FLOAT_DELTA);
         assertArrayEquals(new long[] {firstSensorTime, secondSensorTime}, event.luxTimestamps);
         assertEquals(brightness, event.brightness, FLOAT_DELTA);
@@ -678,6 +690,7 @@
         builder.setTimeStamp(345L);
         builder.setPackageName("com.example");
         builder.setUserId(12);
+        builder.setUniqueDisplayId("9876");
         float[] luxValues = new float[2];
         luxValues[0] = 3000.0f;
         luxValues[1] = 4000.0f;
@@ -710,6 +723,7 @@
         assertEquals(event.timeStamp, event2.timeStamp);
         assertEquals(event.packageName, event2.packageName);
         assertEquals(event.userId, event2.userId);
+        assertEquals(event.uniqueDisplayId, event2.uniqueDisplayId);
         assertArrayEquals(event.luxValues, event2.luxValues, FLOAT_DELTA);
         assertArrayEquals(event.luxTimestamps, event2.luxTimestamps);
         assertEquals(event.batteryLevel, event2.batteryLevel, FLOAT_DELTA);
@@ -773,7 +787,7 @@
         long eventTime = mInjector.currentTimeMillis();
         mTracker.notifyBrightnessChanged(brightness, true /*userInitiated*/,
                 1.0f /*powerBrightnessFactor*/, false /*isUserSetBrightness*/,
-                false /*isDefaultBrightnessConfig*/);
+                false /*isDefaultBrightnessConfig*/, DEFAULT_DISPLAY_ID);
 
         // Time passes before handler can run.
         mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2));
@@ -791,6 +805,35 @@
         assertEquals(eventTime, event.timeStamp);
     }
 
+    @Test
+    public void testDisplayIdChange() {
+        float firstBrightness = 0.5f;
+        float secondBrightness = 0.75f;
+        String firstDisplayId = "123";
+        String secondDisplayId = "456";
+
+        startTracker(mTracker);
+        mInjector.mSensorListener.onSensorChanged(createSensorEvent(1000.0f));
+
+        notifyBrightnessChanged(mTracker, firstBrightness, firstDisplayId);
+        mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2));
+        List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
+        assertEquals(1, events.size());
+        BrightnessChangeEvent firstEvent = events.get(0);
+        assertEquals(firstDisplayId, firstEvent.uniqueDisplayId);
+        assertEquals(firstBrightness, firstEvent.brightness, 0.001f);
+
+        notifyBrightnessChanged(mTracker, secondBrightness, secondDisplayId);
+        mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2));
+        events = mTracker.getEvents(0, true).getList();
+        assertEquals(2, events.size());
+        BrightnessChangeEvent secondEvent = events.get(1);
+        assertEquals(secondDisplayId, secondEvent.uniqueDisplayId);
+        assertEquals(secondBrightness, secondEvent.brightness, 0.001f);
+
+        mTracker.stop();
+    }
+
     private InputStream getInputStream(String data) {
         return new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
     }
@@ -831,16 +874,21 @@
     }
 
     private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness) {
+        notifyBrightnessChanged(tracker, brightness, DEFAULT_DISPLAY_ID);
+    }
+
+    private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness,
+            String displayId) {
         notifyBrightnessChanged(tracker, brightness, true /*userInitiated*/,
                 1.0f /*powerBrightnessFactor*/, false /*isUserSetBrightness*/,
-                false /*isDefaultBrightnessConfig*/);
+                false /*isDefaultBrightnessConfig*/, displayId);
     }
 
     private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness,
             boolean userInitiated, float powerBrightnessFactor, boolean isUserSetBrightness,
-            boolean isDefaultBrightnessConfig) {
+            boolean isDefaultBrightnessConfig, String displayId) {
         tracker.notifyBrightnessChanged(brightness, userInitiated, powerBrightnessFactor,
-                isUserSetBrightness, isDefaultBrightnessConfig);
+                isUserSetBrightness, isDefaultBrightnessConfig, displayId);
         mInjector.waitForHandler();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
index 605f781..53b4b49 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/PowerStatusMonitorActionTest.java
@@ -19,7 +19,6 @@
 import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
 import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
-import static com.android.server.hdmi.Constants.ADDR_TV;
 import static com.android.server.hdmi.HdmiControlService.INITIATED_BY_ENABLE_CEC;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -51,6 +50,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.concurrent.TimeUnit;
 
 /** Tests for {@link ActiveSourceAction} */
@@ -84,7 +84,8 @@
         when(mContextSpy.getSystemService(PowerManager.class)).thenReturn(powerManager);
         when(mIPowerManagerMock.isInteractive()).thenReturn(true);
 
-        mHdmiControlService = new HdmiControlService(mContextSpy) {
+        mHdmiControlService = new HdmiControlService(mContextSpy,
+                Collections.singletonList(HdmiDeviceInfo.DEVICE_TV)) {
             @Override
             AudioManager getAudioManager() {
                 return new AudioManager() {
@@ -140,6 +141,7 @@
         mNativeWrapper.setPhysicalAddress(mPhysicalAddress);
         mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
+        mNativeWrapper.clearResultMessages();
     }
 
     @Test
@@ -152,7 +154,7 @@
         mTestLooper.dispatchAll();
 
         HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
-                ADDR_TV,
+                mTvDevice.mAddress,
                 ADDR_PLAYBACK_1);
         assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
 
@@ -191,7 +193,7 @@
         mTestLooper.dispatchAll();
 
         HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
-                ADDR_TV,
+                mTvDevice.mAddress,
                 ADDR_PLAYBACK_1);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus);
@@ -220,12 +222,12 @@
         mTestLooper.dispatchAll();
 
         HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
-                ADDR_TV,
+                mTvDevice.mAddress,
                 ADDR_PLAYBACK_1);
         assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
 
         HdmiCecMessage giveDevicePowerStatus2 = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
-                ADDR_TV,
+                mTvDevice.mAddress,
                 ADDR_PLAYBACK_2);
         assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus2);
     }
@@ -245,13 +247,13 @@
         mTestLooper.dispatchAll();
 
         HdmiCecMessage giveDevicePowerStatus = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
-                ADDR_TV,
+                mTvDevice.mAddress,
                 ADDR_PLAYBACK_1);
 
         assertThat(mNativeWrapper.getResultMessages()).contains(giveDevicePowerStatus);
 
         HdmiCecMessage giveDevicePowerStatus2 = HdmiCecMessageBuilder.buildGiveDevicePowerStatus(
-                ADDR_TV,
+                mTvDevice.mAddress,
                 ADDR_PLAYBACK_2);
 
         assertThat(mNativeWrapper.getResultMessages()).doesNotContain(giveDevicePowerStatus2);
@@ -265,7 +267,7 @@
     }
 
     private void reportPowerStatus(int logicalAddress, boolean broadcast, int powerStatus) {
-        int destination = broadcast ? ADDR_BROADCAST : ADDR_TV;
+        int destination = broadcast ? ADDR_BROADCAST : mTvDevice.mAddress;
         HdmiCecMessage reportPowerStatus = HdmiCecMessageBuilder.buildReportPowerStatus(
                 logicalAddress, destination,
                 powerStatus);
diff --git a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
index 60390dc..b2dacab 100644
--- a/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
+++ b/services/tests/servicestests/src/com/android/server/usage/UsageStatsDatabaseTest.java
@@ -261,6 +261,7 @@
         // mEndTimeStamp is based on the enclosing IntervalStats, don't bother checking
         assertEquals(us1.mLastTimeUsed, us2.mLastTimeUsed);
         assertEquals(us1.mLastTimeVisible, us2.mLastTimeVisible);
+        assertEquals(us1.mLastTimeComponentUsed, us2.mLastTimeComponentUsed);
         assertEquals(us1.mTotalTimeInForeground, us2.mTotalTimeInForeground);
         assertEquals(us1.mTotalTimeVisible, us2.mTotalTimeVisible);
         assertEquals(us1.mLastTimeForegroundServiceUsed, us2.mLastTimeForegroundServiceUsed);
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerService.java b/services/translation/java/com/android/server/translation/TranslationManagerService.java
index 8874e0a..72e1e33 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerService.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerService.java
@@ -27,6 +27,7 @@
 import android.content.pm.PackageManager;
 import android.os.Binder;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
@@ -203,6 +204,28 @@
             }
         }
 
+        @Override
+        public void registerUiTranslationStateCallback(IRemoteCallback callback, int userId) {
+            TranslationManagerServiceImpl service;
+            synchronized (mLock) {
+                service = getServiceForUserLocked(userId);
+            }
+            if (service != null) {
+                service.registerUiTranslationStateCallback(callback, Binder.getCallingUid());
+            }
+        }
+
+        @Override
+        public void unregisterUiTranslationStateCallback(IRemoteCallback callback, int userId) {
+            TranslationManagerServiceImpl service;
+            synchronized (mLock) {
+                service = getServiceForUserLocked(userId);
+            }
+            if (service != null) {
+                service.unregisterUiTranslationStateCallback(callback);
+            }
+        }
+
         /**
          * Dump the service state into the given stream. You run "adb shell dumpsys translation".
         */
diff --git a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
index ab6ac12..1ca07cb 100644
--- a/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
+++ b/services/translation/java/com/android/server/translation/TranslationManagerServiceImpl.java
@@ -17,17 +17,24 @@
 package com.android.server.translation;
 
 import static android.view.translation.TranslationManager.STATUS_SYNC_CALL_SUCCESS;
+import static android.view.translation.UiTranslationManager.EXTRA_SOURCE_LOCALE;
+import static android.view.translation.UiTranslationManager.EXTRA_STATE;
+import static android.view.translation.UiTranslationManager.EXTRA_TARGET_LOCALE;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.os.Bundle;
 import android.os.IBinder;
+import android.os.IRemoteCallback;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.service.translation.TranslationServiceInfo;
 import android.util.Slog;
 import android.view.autofill.AutofillId;
+import android.view.inputmethod.InputMethodInfo;
 import android.view.translation.TranslationSpec;
 import android.view.translation.UiTranslationManager.UiTranslationState;
 
@@ -36,6 +43,7 @@
 import com.android.internal.util.SyncResultReceiver;
 import com.android.server.LocalServices;
 import com.android.server.infra.AbstractPerUserSystemService;
+import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.ActivityTaskManagerInternal.ActivityTokens;
 
@@ -174,5 +182,50 @@
         } catch (RemoteException e) {
             Slog.w(TAG, "Update UiTranslationState fail: " + e);
         }
+        invokeCallbacks(state, sourceSpec, destSpec);
     }
+
+    private void invokeCallbacks(
+            int state, TranslationSpec sourceSpec, TranslationSpec targetSpec) {
+        Bundle res = new Bundle();
+        res.putInt(EXTRA_STATE, state);
+        // TODO(177500482): Store the locale pair so it can be sent for RESUME events.
+        if (sourceSpec != null) {
+            res.putString(EXTRA_SOURCE_LOCALE, sourceSpec.getLanguage());
+            res.putString(EXTRA_TARGET_LOCALE, targetSpec.getLanguage());
+        }
+        // TODO(177500482): Only support the *current* Input Method.
+        List<InputMethodInfo> enabledInputMethods =
+                LocalServices.getService(InputMethodManagerInternal.class)
+                        .getEnabledInputMethodListAsUser(mUserId);
+        mCallbacks.broadcast((callback, uid) -> {
+            // Code here is non-optimal since it's temporary..
+            boolean isIme = false;
+            for (InputMethodInfo inputMethod : enabledInputMethods) {
+                if ((int) uid == inputMethod.getServiceInfo().applicationInfo.uid) {
+                    isIme = true;
+                }
+            }
+            // TODO(177500482): Invoke it for the application being translated too.
+            if (!isIme) {
+                return;
+            }
+            try {
+                callback.sendResult(res);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed to invoke UiTranslationStateCallback: " + e);
+            }
+        });
+    }
+
+    public void registerUiTranslationStateCallback(IRemoteCallback callback, int sourceUid) {
+        mCallbacks.register(callback, sourceUid);
+        // TODO(177500482): trigger the callback here if we're already translating the UI.
+    }
+
+    public void unregisterUiTranslationStateCallback(IRemoteCallback callback) {
+        mCallbacks.unregister(callback);
+    }
+
+    private final RemoteCallbackList<IRemoteCallback> mCallbacks = new RemoteCallbackList<>();
 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProto.java b/services/usage/java/com/android/server/usage/UsageStatsProto.java
index 78b1477..ec4c5fc 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProto.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProto.java
@@ -147,6 +147,10 @@
                     stats.mTotalTimeVisible = proto.readLong(
                             IntervalStatsProto.UsageStats.TOTAL_TIME_VISIBLE_MS);
                     break;
+                case (int) IntervalStatsProto.UsageStats.LAST_TIME_COMPONENT_USED_MS:
+                    stats.mLastTimeComponentUsed = statsOut.beginTime + proto.readLong(
+                            IntervalStatsProto.UsageStats.LAST_TIME_COMPONENT_USED_MS);
+                    break;
             }
         }
         proto.end(token);
@@ -345,6 +349,9 @@
                 usageStats.mLastTimeVisible, stats.beginTime);
         proto.write(IntervalStatsProto.UsageStats.TOTAL_TIME_VISIBLE_MS,
                 usageStats.mTotalTimeVisible);
+        UsageStatsProtoV2.writeOffsetTimestamp(proto,
+                IntervalStatsProto.UsageStats.LAST_TIME_COMPONENT_USED_MS,
+                usageStats.mLastTimeComponentUsed, stats.beginTime);
         proto.write(IntervalStatsProto.UsageStats.APP_LAUNCH_COUNT, usageStats.mAppLaunchCount);
         try {
             writeChooserCounts(proto, usageStats);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
index e6d2841..5c5667c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsProtoV2.java
@@ -90,6 +90,10 @@
                     stats.mTotalTimeVisible = proto.readLong(
                             UsageStatsObfuscatedProto.TOTAL_TIME_VISIBLE_MS);
                     break;
+                case (int) UsageStatsObfuscatedProto.LAST_TIME_COMPONENT_USED_MS:
+                    stats.mLastTimeComponentUsed = beginTime + proto.readLong(
+                            UsageStatsObfuscatedProto.LAST_TIME_COMPONENT_USED_MS);
+                    break;
                 case ProtoInputStream.NO_MORE_FIELDS:
                     return stats;
             }
@@ -312,6 +316,8 @@
         writeOffsetTimestamp(proto, UsageStatsObfuscatedProto.LAST_TIME_VISIBLE_MS,
                 stats.mLastTimeVisible, beginTime);
         proto.write(UsageStatsObfuscatedProto.TOTAL_TIME_VISIBLE_MS, stats.mTotalTimeVisible);
+        writeOffsetTimestamp(proto, UsageStatsObfuscatedProto.LAST_TIME_COMPONENT_USED_MS,
+                stats.mLastTimeComponentUsed, beginTime);
         proto.write(UsageStatsObfuscatedProto.APP_LAUNCH_COUNT, stats.mAppLaunchCount);
         try {
             writeChooserCounts(proto, stats);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index f35b9e2..22b4f4e 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -1003,6 +1003,8 @@
                     formatElapsedTime(usageStats.mTotalTimeVisible, prettyDates));
             pw.printPair("lastTimeVisible",
                     formatDateTime(usageStats.mLastTimeVisible, prettyDates));
+            pw.printPair("lastTimeComponentUsed",
+                    formatDateTime(usageStats.mLastTimeComponentUsed, prettyDates));
             pw.printPair("totalTimeFS",
                     formatElapsedTime(usageStats.mTotalTimeForegroundServiceUsed, prettyDates));
             pw.printPair("lastTimeFS",
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index c92d40c..3c12aaa 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker.close
 
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -49,7 +50,12 @@
         @JvmStatic
         fun getParams(): List<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 5)
+                .getConfigNonRotationTests(
+                    repetitions = 5,
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 1f880f6..8359ccf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker.close
 
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -49,7 +50,12 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 5)
+                .getConfigNonRotationTests(
+                    repetitions = 5,
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
index f7e7493..fad25b4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
@@ -16,31 +16,13 @@
 
 package com.android.server.wm.flicker.helpers
 
-import android.os.RemoteException
-import android.view.Surface
 import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.rules.ChangeDisplayOrientationRule
 
 /**
  * Changes the device [rotation] and wait for the rotation animation to complete
  *
  * @param rotation New device rotation
  */
-fun Flicker.setRotation(rotation: Int) {
-    try {
-        when (rotation) {
-            Surface.ROTATION_270 -> device.setOrientationRight()
-            Surface.ROTATION_90 -> device.setOrientationLeft()
-            Surface.ROTATION_0 -> device.setOrientationNatural()
-            else -> device.setOrientationNatural()
-        }
-
-        wmHelper.waitForRotation(rotation)
-        wmHelper.waitForNavBarStatusBarVisible()
-        wmHelper.waitForAppTransitionIdle()
-
-        // Ensure WindowManagerService wait until all animations have completed
-        instrumentation.uiAutomation.syncInputTransactions()
-    } catch (e: RemoteException) {
-        throw RuntimeException(e)
-    }
-}
\ No newline at end of file
+fun Flicker.setRotation(rotation: Int) =
+    ChangeDisplayOrientationRule.setRotation(rotation, instrumentation, wmHelper)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 47eaddf..0dcc8c9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -20,6 +20,7 @@
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
@@ -164,7 +165,12 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 5)
+                .getConfigNonRotationTests(
+                    repetitions = 5,
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 26afb79..7a1bb11 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -19,6 +19,7 @@
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
@@ -178,7 +179,12 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 5)
+                .getConfigNonRotationTests(
+                    repetitions = 5,
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index 2c4c627..2d09d23 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -19,6 +19,7 @@
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.wm.flicker.FlickerBuilderProvider
@@ -141,7 +142,12 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 5)
+                .getConfigNonRotationTests(
+                    repetitions = 5,
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 2bcdcd9..73760c5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -19,6 +19,7 @@
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
@@ -162,8 +163,13 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 5,
-                    supportedRotations = listOf(Surface.ROTATION_0))
+                .getConfigNonRotationTests(
+                    repetitions = 5,
+                    supportedRotations = listOf(Surface.ROTATION_0),
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index 6b2b930..2815e05 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -19,6 +19,7 @@
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
@@ -168,8 +169,13 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 5,
-                    supportedRotations = listOf(Surface.ROTATION_0))
+                .getConfigNonRotationTests(
+                    repetitions = 5,
+                    supportedRotations = listOf(Surface.ROTATION_0),
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 0cd5d79..7ca985e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -19,6 +19,7 @@
 import android.app.Instrumentation
 import android.platform.test.annotations.Presubmit
 import android.view.Surface
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
@@ -184,7 +185,12 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 1)
+                .getConfigNonRotationTests(
+                    repetitions = 1,
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 56ed21b..417a5c5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker.launch
 
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -60,7 +61,12 @@
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+            return FlickerTestParameterFactory.getInstance()
+                .getConfigNonRotationTests(
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 4a32a9e..fee01d2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -17,6 +17,7 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -136,7 +137,12 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(repetitions = 5)
+                .getConfigNonRotationTests(
+                    repetitions = 5,
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index a8b5ea1..bdae810 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.wm.flicker.launch
 
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -72,7 +73,12 @@
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+            return FlickerTestParameterFactory.getInstance()
+                .getConfigNonRotationTests(
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 6985b36..80b2237 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -17,6 +17,7 @@
 package com.android.server.wm.flicker.rotation
 
 import android.platform.test.annotations.Presubmit
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.FlickerTestParameter
@@ -70,7 +71,12 @@
         @JvmStatic
         fun getParams(): Collection<FlickerTestParameter> {
             return FlickerTestParameterFactory.getInstance()
-                .getConfigRotationTests(repetitions = 5)
+                .getConfigRotationTests(
+                    repetitions = 5,
+                    supportedNavigationModes = listOf(
+                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                    )
+                )
         }
     }
 }
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index 45d3006..dd7103c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -17,6 +17,7 @@
 package com.android.server.wm.flicker.rotation
 
 import android.platform.test.annotations.Presubmit
+import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.FlakyTest
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -103,7 +104,12 @@
 
         @JvmStatic
         private fun getConfigurations(): List<FlickerTestParameter> {
-            return testFactory.getConfigRotationTests(repetitions = 2).flatMap {
+            return testFactory.getConfigRotationTests(
+                repetitions = 2,
+                supportedNavigationModes = listOf(
+                    WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+                )
+            ).flatMap {
                 val defaultRun = it.createConfig(starveUiThread = false)
                 val busyUiRun = it.createConfig(starveUiThread = true)
                 listOf(