Merge "Clean up some unnecessary methods of ActivityRecord" into main
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 7370fc3..5b044f6 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -119,7 +119,7 @@
 
     oneway void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
     oneway void setInheritShowWhenLocked(in IBinder token, boolean setInheritShownWhenLocked);
-    oneway void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
+    void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
     oneway void setAllowCrossUidActivitySwitchFromBelow(in IBinder token, boolean allowed);
     oneway void reportActivityFullyDrawn(in IBinder token, boolean restoredFromBundle);
     oneway void overrideActivityTransition(IBinder token, boolean open, int enterAnim, int exitAnim,
diff --git a/core/java/android/app/backup/BackupHelperWithLogger.java b/core/java/android/app/backup/BackupHelperWithLogger.java
new file mode 100644
index 0000000..1a59a53
--- /dev/null
+++ b/core/java/android/app/backup/BackupHelperWithLogger.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 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.app.backup;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Utility class for writing BackupHelpers with added logging capabilities.
+ * Used for passing a logger object to Helper in key shared backup agents
+ *
+ * @hide
+ */
+public abstract class BackupHelperWithLogger implements BackupHelper {
+    private BackupRestoreEventLogger mLogger;
+    private boolean mIsLoggerSet = false;
+
+    public abstract void writeNewStateDescription(ParcelFileDescriptor newState);
+
+    public abstract void restoreEntity(BackupDataInputStream data);
+
+    public abstract void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState);
+
+    /**
+     * Gets the logger so that the backuphelper can log success/error for each datatype handled
+     */
+    public BackupRestoreEventLogger getLogger() {
+        return mLogger;
+    }
+
+    /**
+     * Allow the shared backup agent to pass a logger to each of its backup helper
+     */
+    public void setLogger(BackupRestoreEventLogger logger) {
+        mLogger = logger;
+        mIsLoggerSet = true;
+    }
+
+    /**
+     * Allow the helper to check if its shared backup agent has passed a logger
+     */
+    public boolean isLoggerSet() {
+        return mIsLoggerSet;
+    }
+}
diff --git a/core/java/android/app/backup/BlobBackupHelper.java b/core/java/android/app/backup/BlobBackupHelper.java
index 82d0a94c..a55ff48 100644
--- a/core/java/android/app/backup/BlobBackupHelper.java
+++ b/core/java/android/app/backup/BlobBackupHelper.java
@@ -39,7 +39,7 @@
  *
  * @hide
  */
-public abstract class BlobBackupHelper implements BackupHelper {
+public abstract class BlobBackupHelper extends BackupHelperWithLogger {
     private static final String TAG = "BlobBackupHelper";
     private static final boolean DEBUG = false;
 
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index c20b278..7f5331b 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -167,6 +167,11 @@
                     + ", reported config=" + currentConfig
                     + ", updated config=" + newConfig);
         }
+        // Update display first. In case callers want to obtain display information(
+        // ex: DisplayMetrics) in #onConfigurationChanged callback.
+        if (displayChanged) {
+            context.updateDisplay(newDisplayId);
+        }
         if (shouldUpdateResources) {
             // TODO(ag/9789103): update resource manager logic to track non-activity tokens
             mResourcesManager.updateResourcesForActivity(this, newConfig, newDisplayId);
@@ -195,9 +200,6 @@
                 }
             }
         }
-        if (displayChanged) {
-            context.updateDisplay(newDisplayId);
-        }
     }
 
     /**
diff --git a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
index ce9ab82..2ff6225 100644
--- a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
+++ b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
@@ -21,6 +21,7 @@
 import android.app.backup.BackupDataInputStream;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupHelper;
+import android.app.backup.BackupHelperWithLogger;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.SyncAdapterType;
@@ -56,7 +57,7 @@
  * sync settings are backed up as a JSON object containing all the necessary information for
  * restoring the sync settings later.
  */
-public class AccountSyncSettingsBackupHelper implements BackupHelper {
+public class AccountSyncSettingsBackupHelper extends BackupHelperWithLogger {
 
     private static final String TAG = "AccountSyncSettingsBackupHelper";
     private static final boolean DEBUG = false;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index 83d555c..14a4677 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -17,6 +17,7 @@
 package androidx.window.extensions.embedding;
 
 import static android.app.ActivityManager.START_SUCCESS;
+import static android.app.ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -110,6 +111,10 @@
     static final boolean ENABLE_SHELL_TRANSITIONS =
             SystemProperties.getBoolean("persist.wm.debug.shell_transit", true);
 
+    // TODO(b/295993745): remove after prebuilt library is updated.
+    private static final String KEY_ACTIVITY_STACK_TOKEN =
+            "androidx.window.extensions.embedding.ActivityStackToken";
+
     @VisibleForTesting
     @GuardedBy("mLock")
     final SplitPresenter mPresenter;
@@ -2779,8 +2784,17 @@
             // TODO(b/232042367): Consolidate the activity create handling so that we can handle
             // cross-process the same as normal.
 
+            IBinder activityStackToken = options.getBinder(KEY_ACTIVITY_STACK_TOKEN);
+            if (activityStackToken != null) {
+                // Put activityStack token to #KEY_LAUNCH_TASK_FRAGMENT_TOKEN to launch the activity
+                // into the taskFragment associated with the token.
+                options.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN, activityStackToken);
+            }
+
             // Early return if the launching taskfragment is already been set.
-            if (options.getBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN) != null) {
+            // TODO(b/295993745): Use KEY_LAUNCH_TASK_FRAGMENT_TOKEN after WM Jetpack migrates to
+            // bundle. This is still needed to support #setLaunchingActivityStack.
+            if (options.getBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN) != null) {
                 synchronized (mLock) {
                     mCurrentIntent = intent;
                 }
@@ -2837,7 +2851,7 @@
                     // Amend the request to let the WM know that the activity should be placed in
                     // the dedicated container.
                     // TODO(b/229680885): skip override launching TaskFragment token by split-rule
-                    options.putBinder(ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
+                    options.putBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN,
                             launchedInTaskFragment.getTaskFragmentToken());
                     mCurrentIntent = intent;
                 } else {
@@ -2855,8 +2869,7 @@
                 if (mCurrentIntent != null && result != START_SUCCESS) {
                     // Clear the pending appeared intent if the activity was not started
                     // successfully.
-                    final IBinder token = bOptions.getBinder(
-                            ActivityOptions.KEY_LAUNCH_TASK_FRAGMENT_TOKEN);
+                    final IBinder token = bOptions.getBinder(KEY_LAUNCH_TASK_FRAGMENT_TOKEN);
                     if (token != null) {
                         final TaskFragmentContainer container = getContainer(token);
                         if (container != null) {
diff --git a/media/java/android/media/tv/ad/ITvAdManager.aidl b/media/java/android/media/tv/ad/ITvAdManager.aidl
index c4806fb..a747e49 100644
--- a/media/java/android/media/tv/ad/ITvAdManager.aidl
+++ b/media/java/android/media/tv/ad/ITvAdManager.aidl
@@ -16,7 +16,6 @@
 
 package android.media.tv.ad;
 
-import android.graphics.Rect;
 import android.media.tv.ad.ITvAdClient;
 import android.media.tv.ad.ITvAdManagerCallback;
 import android.media.tv.ad.TvAdServiceInfo;
@@ -38,9 +37,4 @@
 
     void registerCallback(in ITvAdManagerCallback callback, int userId);
     void unregisterCallback(in ITvAdManagerCallback callback, int userId);
-
-    void createMediaView(in IBinder sessionToken, in IBinder windowToken, in Rect frame,
-            int userId);
-    void relayoutMediaView(in IBinder sessionToken, in Rect frame, int userId);
-    void removeMediaView(in IBinder sessionToken, int userId);
 }
diff --git a/media/java/android/media/tv/ad/ITvAdSession.aidl b/media/java/android/media/tv/ad/ITvAdSession.aidl
index 3ca0198..751257c 100644
--- a/media/java/android/media/tv/ad/ITvAdSession.aidl
+++ b/media/java/android/media/tv/ad/ITvAdSession.aidl
@@ -16,7 +16,6 @@
 
 package android.media.tv.ad;
 
-import android.graphics.Rect;
 import android.view.Surface;
 
 /**
@@ -28,8 +27,4 @@
     void startAdService();
     void setSurface(in Surface surface);
     void dispatchSurfaceChanged(int format, int width, int height);
-
-    void createMediaView(in IBinder windowToken, in Rect frame);
-    void relayoutMediaView(in Rect frame);
-    void removeMediaView();
 }
diff --git a/media/java/android/media/tv/ad/ITvAdSessionWrapper.java b/media/java/android/media/tv/ad/ITvAdSessionWrapper.java
index 3d5bc89..4df2783 100644
--- a/media/java/android/media/tv/ad/ITvAdSessionWrapper.java
+++ b/media/java/android/media/tv/ad/ITvAdSessionWrapper.java
@@ -17,8 +17,6 @@
 package android.media.tv.ad;
 
 import android.content.Context;
-import android.graphics.Rect;
-import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
@@ -45,9 +43,6 @@
     private static final int DO_RELEASE = 1;
     private static final int DO_SET_SURFACE = 2;
     private static final int DO_DISPATCH_SURFACE_CHANGED = 3;
-    private static final int DO_CREATE_MEDIA_VIEW = 4;
-    private static final int DO_RELAYOUT_MEDIA_VIEW = 5;
-    private static final int DO_REMOVE_MEDIA_VIEW = 6;
 
     private final HandlerCaller mCaller;
     private TvAdService.Session mSessionImpl;
@@ -66,7 +61,6 @@
 
     @Override
     public void release() {
-        mSessionImpl.scheduleMediaViewCleanup();
         mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_RELEASE));
     }
 
@@ -103,20 +97,6 @@
                 args.recycle();
                 break;
             }
-            case DO_CREATE_MEDIA_VIEW: {
-                SomeArgs args = (SomeArgs) msg.obj;
-                mSessionImpl.createMediaView((IBinder) args.arg1, (Rect) args.arg2);
-                args.recycle();
-                break;
-            }
-            case DO_RELAYOUT_MEDIA_VIEW: {
-                mSessionImpl.relayoutMediaView((Rect) msg.obj);
-                break;
-            }
-            case DO_REMOVE_MEDIA_VIEW: {
-                mSessionImpl.removeMediaView(true);
-                break;
-            }
             default: {
                 Log.w(TAG, "Unhandled message code: " + msg.what);
                 break;
@@ -149,22 +129,6 @@
                 mCaller.obtainMessageIIII(DO_DISPATCH_SURFACE_CHANGED, format, width, height, 0));
     }
 
-    @Override
-    public void createMediaView(IBinder windowToken, Rect frame) {
-        mCaller.executeOrSendMessage(
-                mCaller.obtainMessageOO(DO_CREATE_MEDIA_VIEW, windowToken, frame));
-    }
-
-    @Override
-    public void relayoutMediaView(Rect frame) {
-        mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_RELAYOUT_MEDIA_VIEW, frame));
-    }
-
-    @Override
-    public void removeMediaView() {
-        mCaller.executeOrSendMessage(mCaller.obtainMessage(DO_REMOVE_MEDIA_VIEW));
-    }
-
     private final class TvAdEventReceiver extends InputEventReceiver {
         TvAdEventReceiver(InputChannel inputChannel, Looper looper) {
             super(inputChannel, looper);
diff --git a/media/java/android/media/tv/ad/TvAdManager.java b/media/java/android/media/tv/ad/TvAdManager.java
index b2ea00d..9c75051 100644
--- a/media/java/android/media/tv/ad/TvAdManager.java
+++ b/media/java/android/media/tv/ad/TvAdManager.java
@@ -21,7 +21,6 @@
 import android.annotation.Nullable;
 import android.annotation.SystemService;
 import android.content.Context;
-import android.graphics.Rect;
 import android.media.tv.TvInputManager;
 import android.media.tv.flags.Flags;
 import android.os.Handler;
@@ -36,7 +35,6 @@
 import android.view.InputEvent;
 import android.view.InputEventSender;
 import android.view.Surface;
-import android.view.View;
 
 import com.android.internal.util.Preconditions;
 
@@ -288,67 +286,6 @@
         }
 
         /**
-         * Creates a media view. Once the media view is created, {@link #relayoutMediaView}
-         * should be called whenever the layout of its containing view is changed.
-         * {@link #removeMediaView()} should be called to remove the media view.
-         * Since a session can have only one media view, this method should be called only once
-         * or it can be called again after calling {@link #removeMediaView()}.
-         *
-         * @param view A view for AD service.
-         * @param frame A position of the media view.
-         * @throws IllegalStateException if {@code view} is not attached to a window.
-         */
-        void createMediaView(@NonNull View view, @NonNull Rect frame) {
-            Preconditions.checkNotNull(view);
-            Preconditions.checkNotNull(frame);
-            if (view.getWindowToken() == null) {
-                throw new IllegalStateException("view must be attached to a window");
-            }
-            if (mToken == null) {
-                Log.w(TAG, "The session has been already released");
-                return;
-            }
-            try {
-                mService.createMediaView(mToken, view.getWindowToken(), frame, mUserId);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-
-        /**
-         * Relayouts the current media view.
-         *
-         * @param frame A new position of the media view.
-         */
-        void relayoutMediaView(@NonNull Rect frame) {
-            Preconditions.checkNotNull(frame);
-            if (mToken == null) {
-                Log.w(TAG, "The session has been already released");
-                return;
-            }
-            try {
-                mService.relayoutMediaView(mToken, frame, mUserId);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-
-        /**
-         * Removes the current media view.
-         */
-        void removeMediaView() {
-            if (mToken == null) {
-                Log.w(TAG, "The session has been already released");
-                return;
-            }
-            try {
-                mService.removeMediaView(mToken, mUserId);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
-        }
-
-        /**
          * Notifies of any structural changes (format or size) of the surface passed in
          * {@link #setSurface}.
          *
diff --git a/media/java/android/media/tv/ad/TvAdService.java b/media/java/android/media/tv/ad/TvAdService.java
index 6f7f67d..6995703 100644
--- a/media/java/android/media/tv/ad/TvAdService.java
+++ b/media/java/android/media/tv/ad/TvAdService.java
@@ -20,25 +20,19 @@
 import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.Px;
 import android.annotation.SdkConstant;
 import android.annotation.SuppressLint;
-import android.app.ActivityManager;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
-import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.util.Log;
-import android.view.Gravity;
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.InputEvent;
@@ -48,7 +42,6 @@
 import android.view.Surface;
 import android.view.View;
 import android.view.WindowManager;
-import android.widget.FrameLayout;
 
 import com.android.internal.os.SomeArgs;
 
@@ -63,8 +56,6 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "TvAdService";
 
-    private static final int DETACH_MEDIA_VIEW_TIMEOUT_MS = 5000;
-
     /**
      * Name under which a TvAdService component publishes information about itself. This meta-data
      * must reference an XML resource containing an
@@ -160,14 +151,7 @@
         private final Context mContext;
         final Handler mHandler;
         private final WindowManager mWindowManager;
-        private WindowManager.LayoutParams mWindowParams;
         private Surface mSurface;
-        private FrameLayout mMediaViewContainer;
-        private View mMediaView;
-        private MediaViewCleanUpTask mMediaViewCleanUpTask;
-        private boolean mMediaViewEnabled;
-        private IBinder mWindowToken;
-        private Rect mMediaFrame;
 
 
         /**
@@ -182,48 +166,6 @@
         }
 
         /**
-         * Enables or disables the media view.
-         *
-         * <p>By default, the media view is disabled. Must be called explicitly after the
-         * session is created to enable the media view.
-         *
-         * <p>The TV AD service can disable its media view when needed.
-         *
-         * @param enable {@code true} if you want to enable the media view. {@code false}
-         *            otherwise.
-         * @hide
-         */
-        @CallSuper
-        public void setMediaViewEnabled(final boolean enable) {
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    if (enable == mMediaViewEnabled) {
-                        return;
-                    }
-                    mMediaViewEnabled = enable;
-                    if (enable) {
-                        if (mWindowToken != null) {
-                            createMediaView(mWindowToken, mMediaFrame);
-                        }
-                    } else {
-                        removeMediaView(false);
-                    }
-                }
-            });
-        }
-
-        /**
-         * Returns {@code true} if media view is enabled, {@code false} otherwise.
-         *
-         * @see #setMediaViewEnabled(boolean)
-         * @hide
-         */
-        public boolean isMediaViewEnabled() {
-            return mMediaViewEnabled;
-        }
-
-        /**
          * Releases TvAdService session.
          */
         public abstract void onRelease();
@@ -238,9 +180,6 @@
                 mSessionCallback = null;
                 mPendingActions.clear();
             }
-            // Removes the media view lastly so that any hanging on the main thread can be handled
-            // in {@link #scheduleMediaViewCleanup}.
-            removeMediaView(true);
         }
 
         /**
@@ -368,33 +307,6 @@
         }
 
         /**
-         * Called when the size of the media view is changed by the application.
-         *
-         * <p>This is always called at least once when the session is created regardless of whether
-         * the media view is enabled or not. The media view container size is the same as the
-         * containing {@link TvAdView}. Note that the size of the underlying surface can
-         * be different if the surface was changed by calling {@link #layoutSurface}.
-         *
-         * @param width The width of the media view, in pixels.
-         * @param height The height of the media view, in pixels.
-         * @hide
-         */
-        public void onMediaViewSizeChanged(@Px int width, @Px int height) {
-        }
-
-        /**
-         * Called when the application requests to create a media view. Each session
-         * implementation can override this method and return its own view.
-         *
-         * @return a view attached to the media window. {@code null} if no media view is created.
-         * @hide
-         */
-        @Nullable
-        public View onCreateMediaView() {
-            return null;
-        }
-
-        /**
          * Takes care of dispatching incoming input events and tells whether the event was handled.
          */
         int dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {
@@ -476,137 +388,6 @@
                 }
             }
         }
-
-        /**
-         * Creates a media view. This calls {@link #onCreateMediaView} to get a view to attach
-         * to the media window.
-         *
-         * @param windowToken A window token of the application.
-         * @param frame A position of the media view.
-         */
-        void createMediaView(IBinder windowToken, Rect frame) {
-            if (mMediaViewContainer != null) {
-                removeMediaView(false);
-            }
-            if (DEBUG) Log.d(TAG, "create media view(" + frame + ")");
-            mWindowToken = windowToken;
-            mMediaFrame = frame;
-            onMediaViewSizeChanged(frame.right - frame.left, frame.bottom - frame.top);
-            if (!mMediaViewEnabled) {
-                return;
-            }
-            mMediaView = onCreateMediaView();
-            if (mMediaView == null) {
-                return;
-            }
-            if (mMediaViewCleanUpTask != null) {
-                mMediaViewCleanUpTask.cancel(true);
-                mMediaViewCleanUpTask = null;
-            }
-            // Creates a container view to check hanging on the media view detaching.
-            // Adding/removing the media view to/from the container make the view attach/detach
-            // logic run on the main thread.
-            mMediaViewContainer = new FrameLayout(mContext.getApplicationContext());
-            mMediaViewContainer.addView(mMediaView);
-
-            int type = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
-            // We make the overlay view non-focusable and non-touchable so that
-            // the application that owns the window token can decide whether to consume or
-            // dispatch the input events.
-            int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-            if (ActivityManager.isHighEndGfx()) {
-                flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-            }
-            mWindowParams = new WindowManager.LayoutParams(
-                    frame.right - frame.left, frame.bottom - frame.top,
-                    frame.left, frame.top, type, flags, PixelFormat.TRANSPARENT);
-            mWindowParams.privateFlags |=
-                    WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
-            mWindowParams.gravity = Gravity.START | Gravity.TOP;
-            mWindowParams.token = windowToken;
-            mWindowManager.addView(mMediaViewContainer, mWindowParams);
-        }
-
-        /**
-         * Relayouts the current media view.
-         *
-         * @param frame A new position of the media view.
-         */
-        void relayoutMediaView(Rect frame) {
-            if (DEBUG) Log.d(TAG, "relayoutMediaView(" + frame + ")");
-            if (mMediaFrame == null || mMediaFrame.width() != frame.width()
-                    || mMediaFrame.height() != frame.height()) {
-                // Note: relayoutMediaView is called whenever TvAdView's layout is
-                // changed regardless of setMediaViewEnabled.
-                onMediaViewSizeChanged(frame.right - frame.left, frame.bottom - frame.top);
-            }
-            mMediaFrame = frame;
-            if (!mMediaViewEnabled || mMediaViewContainer == null) {
-                return;
-            }
-            mWindowParams.x = frame.left;
-            mWindowParams.y = frame.top;
-            mWindowParams.width = frame.right - frame.left;
-            mWindowParams.height = frame.bottom - frame.top;
-            mWindowManager.updateViewLayout(mMediaViewContainer, mWindowParams);
-        }
-
-        /**
-         * Removes the current media view.
-         */
-        void removeMediaView(boolean clearWindowToken) {
-            if (DEBUG) Log.d(TAG, "removeMediaView(" + mMediaViewContainer + ")");
-            if (clearWindowToken) {
-                mWindowToken = null;
-                mMediaFrame = null;
-            }
-            if (mMediaViewContainer != null) {
-                // Removes the media view from the view hierarchy in advance so that it can be
-                // cleaned up in the {@link MediaViewCleanUpTask} if the remove process is
-                // hanging.
-                mMediaViewContainer.removeView(mMediaView);
-                mMediaView = null;
-                mWindowManager.removeView(mMediaViewContainer);
-                mMediaViewContainer = null;
-                mWindowParams = null;
-            }
-        }
-
-        /**
-         * Schedules a task which checks whether the media view is detached and kills the process
-         * if it is not. Note that this method is expected to be called in a non-main thread.
-         */
-        void scheduleMediaViewCleanup() {
-            View mediaViewParent = mMediaViewContainer;
-            if (mediaViewParent != null) {
-                mMediaViewCleanUpTask = new MediaViewCleanUpTask();
-                mMediaViewCleanUpTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
-                        mediaViewParent);
-            }
-        }
-    }
-
-    private static final class MediaViewCleanUpTask extends AsyncTask<View, Void, Void> {
-        @Override
-        protected Void doInBackground(View... views) {
-            View mediaViewParent = views[0];
-            try {
-                Thread.sleep(DETACH_MEDIA_VIEW_TIMEOUT_MS);
-            } catch (InterruptedException e) {
-                return null;
-            }
-            if (isCancelled()) {
-                return null;
-            }
-            if (mediaViewParent.isAttachedToWindow()) {
-                Log.e(TAG, "Time out on releasing media view. Killing "
-                        + mediaViewParent.getContext().getPackageName());
-                android.os.Process.killProcess(Process.myPid());
-            }
-            return null;
-        }
     }
 
 
diff --git a/media/java/android/media/tv/ad/TvAdView.java b/media/java/android/media/tv/ad/TvAdView.java
index 5e4a70b..5e67fe9 100644
--- a/media/java/android/media/tv/ad/TvAdView.java
+++ b/media/java/android/media/tv/ad/TvAdView.java
@@ -22,8 +22,6 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
-import android.graphics.RectF;
 import android.os.Handler;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -66,9 +64,6 @@
     private int mSurfaceViewTop;
     private int mSurfaceViewBottom;
 
-    private boolean mMediaViewCreated;
-    private Rect mMediaViewFrame;
-
 
 
     private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
@@ -126,20 +121,6 @@
         mTvAdManager = (TvAdManager) getContext().getSystemService(Context.TV_AD_SERVICE);
     }
 
-    /** @hide */
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        createSessionMediaView();
-    }
-
-    /** @hide */
-    @Override
-    public void onDetachedFromWindow() {
-        removeSessionMediaView();
-        super.onDetachedFromWindow();
-    }
-
     @Override
     public void onLayout(boolean changed, int left, int top, int right, int bottom) {
         if (DEBUG) {
@@ -169,11 +150,6 @@
     public void onVisibilityChanged(@NonNull View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
         mSurfaceView.setVisibility(visibility);
-        if (visibility == View.VISIBLE) {
-            createSessionMediaView();
-        } else {
-            removeSessionMediaView();
-        }
     }
 
     private void resetSurfaceView() {
@@ -186,7 +162,6 @@
             @Override
             protected void updateSurface() {
                 super.updateSurface();
-                relayoutSessionMediaView();
             }};
         // The surface view's content should be treated as secure all the time.
         mSurfaceView.setSecure(true);
@@ -199,69 +174,6 @@
         addView(mSurfaceView);
     }
 
-    /**
-     * Resets this TvAdView to release its resources.
-     *
-     * <p>It can be reused by call {@link #prepareAdService(String, String)}.
-     * @hide
-     */
-    public void reset() {
-        if (DEBUG) Log.d(TAG, "reset()");
-        resetInternal();
-    }
-
-    private void resetInternal() {
-        mSessionCallback = null;
-        if (mSession != null) {
-            setSessionSurface(null);
-            removeSessionMediaView();
-            mUseRequestedSurfaceLayout = false;
-            mSession.release();
-            mSession = null;
-            resetSurfaceView();
-        }
-    }
-
-    private void createSessionMediaView() {
-        // TODO: handle z-order
-        if (mSession == null || !isAttachedToWindow() || mMediaViewCreated) {
-            return;
-        }
-        mMediaViewFrame = getViewFrameOnScreen();
-        mSession.createMediaView(this, mMediaViewFrame);
-        mMediaViewCreated = true;
-    }
-
-    private void removeSessionMediaView() {
-        if (mSession == null || !mMediaViewCreated) {
-            return;
-        }
-        mSession.removeMediaView();
-        mMediaViewCreated = false;
-        mMediaViewFrame = null;
-    }
-
-    private void relayoutSessionMediaView() {
-        if (mSession == null || !isAttachedToWindow() || !mMediaViewCreated) {
-            return;
-        }
-        Rect viewFrame = getViewFrameOnScreen();
-        if (viewFrame.equals(mMediaViewFrame)) {
-            return;
-        }
-        mSession.relayoutMediaView(viewFrame);
-        mMediaViewFrame = viewFrame;
-    }
-
-    private Rect getViewFrameOnScreen() {
-        Rect frame = new Rect();
-        getGlobalVisibleRect(frame);
-        RectF frameF = new RectF(frame);
-        getMatrix().mapRect(frameF);
-        frameF.round(frame);
-        return frame;
-    }
-
     private void setSessionSurface(Surface surface) {
         if (mSession == null) {
             return;
@@ -273,7 +185,7 @@
         if (mSession == null) {
             return;
         }
-        mSession.dispatchSurfaceChanged(format, width, height);
+        //mSession.dispatchSurfaceChanged(format, width, height);
     }
 
     /**
@@ -334,7 +246,6 @@
                         dispatchSurfaceChanged(mSurfaceFormat, mSurfaceWidth, mSurfaceHeight);
                     }
                 }
-                createSessionMediaView();
             } else {
                 // Failed to create
                 // Todo: forward error to Tv App
@@ -351,8 +262,6 @@
                 Log.w(TAG, "onSessionReleased - session not created");
                 return;
             }
-            mMediaViewCreated = false;
-            mMediaViewFrame = null;
             mSessionCallback = null;
             mSession = null;
         }
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
index 2052e2c..a7557d8 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -17,6 +17,7 @@
 
 package com.android.systemui.compose
 
+import android.app.Dialog
 import android.content.Context
 import android.view.View
 import android.view.WindowInsets
@@ -26,11 +27,13 @@
 import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
 import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
 import com.android.systemui.communal.widgets.WidgetConfigurator
+import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
 import com.android.systemui.people.ui.viewmodel.PeopleViewModel
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
 import com.android.systemui.scene.shared.model.Scene
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import com.android.systemui.statusbar.phone.SystemUIDialogFactory
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.StateFlow
 
@@ -78,6 +81,13 @@
         throwComposeUnavailableError()
     }
 
+    override fun createStickyKeysDialog(
+        dialogFactory: SystemUIDialogFactory,
+        viewModel: StickyKeysIndicatorViewModel
+    ): Dialog {
+        throwComposeUnavailableError()
+    }
+
     override fun createCommunalView(
         context: Context,
         viewModel: BaseCommunalViewModel,
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
index b607d59..d63939d 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/compose/ComposeFacade.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.compose
 
+import android.app.Dialog
 import android.content.Context
 import android.graphics.Point
 import android.view.View
@@ -38,6 +39,8 @@
 import com.android.systemui.communal.ui.compose.CommunalHub
 import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
 import com.android.systemui.communal.widgets.WidgetConfigurator
+import com.android.systemui.keyboard.stickykeys.ui.view.StickyKeysIndicator
+import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
 import com.android.systemui.people.ui.compose.PeopleScreen
 import com.android.systemui.people.ui.viewmodel.PeopleViewModel
 import com.android.systemui.qs.footer.ui.compose.FooterActions
@@ -47,6 +50,8 @@
 import com.android.systemui.scene.ui.composable.ComposableScene
 import com.android.systemui.scene.ui.composable.SceneContainer
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import com.android.systemui.statusbar.phone.SystemUIDialogFactory
+import com.android.systemui.statusbar.phone.create
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
@@ -120,6 +125,13 @@
         }
     }
 
+    override fun createStickyKeysDialog(
+        dialogFactory: SystemUIDialogFactory,
+        viewModel: StickyKeysIndicatorViewModel
+    ): Dialog {
+        return dialogFactory.create { StickyKeysIndicator(viewModel) }
+    }
+
     override fun createCommunalView(
         context: Context,
         viewModel: BaseCommunalViewModel,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt
new file mode 100644
index 0000000..68e57b5
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyboard/stickykeys/ui/view/StickyKeysIndicator.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.stickykeys.ui.view
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Surface
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.dp
+import com.android.systemui.keyboard.stickykeys.shared.model.Locked
+import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey
+import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
+
+@Composable
+fun StickyKeysIndicator(viewModel: StickyKeysIndicatorViewModel) {
+    val stickyKeys by viewModel.indicatorContent.collectAsState(emptyMap())
+    StickyKeysIndicator(stickyKeys)
+}
+
+@Composable
+fun StickyKeysIndicator(stickyKeys: Map<ModifierKey, Locked>, modifier: Modifier = Modifier) {
+    Surface(
+        color = MaterialTheme.colorScheme.surface,
+        shape = MaterialTheme.shapes.medium,
+        modifier = modifier
+    ) {
+        Column(
+            horizontalAlignment = Alignment.CenterHorizontally,
+            modifier = Modifier.padding(16.dp)
+        ) {
+            stickyKeys.forEach { (key, isLocked) ->
+                key(key) {
+                    Text(
+                        text = key.text,
+                        fontWeight = if (isLocked.locked) FontWeight.Bold else FontWeight.Normal
+                    )
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
index 641064b..2f9fd2e 100644
--- a/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
+++ b/packages/SystemUI/src/com/android/systemui/compose/BaseComposeFacade.kt
@@ -17,6 +17,7 @@
 
 package com.android.systemui.compose
 
+import android.app.Dialog
 import android.content.Context
 import android.view.View
 import android.view.WindowInsets
@@ -26,11 +27,13 @@
 import com.android.systemui.bouncer.ui.viewmodel.BouncerViewModel
 import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
 import com.android.systemui.communal.widgets.WidgetConfigurator
+import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
 import com.android.systemui.people.ui.viewmodel.PeopleViewModel
 import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel
 import com.android.systemui.scene.shared.model.Scene
 import com.android.systemui.scene.shared.model.SceneKey
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import com.android.systemui.statusbar.phone.SystemUIDialogFactory
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.StateFlow
 
@@ -86,6 +89,12 @@
         sceneByKey: Map<SceneKey, Scene>,
     ): View
 
+    /** Creates sticky key dialog presenting provided [viewModel] **/
+    fun createStickyKeysDialog(
+        dialogFactory: SystemUIDialogFactory,
+        viewModel: StickyKeysIndicatorViewModel
+    ): Dialog
+
     /** Create a [View] to represent [viewModel] on screen. */
     fun createCommunalView(
         context: Context,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt
index 37034f6..4ed8120 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/StickyKeysLogger.kt
@@ -26,11 +26,20 @@
 private const val TAG = "stickyKeys"
 
 class StickyKeysLogger @Inject constructor(@KeyboardLog private val buffer: LogBuffer) {
-    fun logNewStickyKeysReceived(linkedHashMap: Map<ModifierKey, Locked>) {
+    fun logNewStickyKeysReceived(stickyKeys: Map<ModifierKey, Locked>) {
         buffer.log(
             TAG,
             LogLevel.VERBOSE,
-            { str1 = linkedHashMap.toString() },
+            { str1 = stickyKeys.toString() },
+            { "new sticky keys state received: $str1" }
+        )
+    }
+
+    fun logNewUiState(stickyKeys: Map<ModifierKey, Locked>) {
+        buffer.log(
+            TAG,
+            LogLevel.INFO,
+            { str1 = stickyKeys.toString() },
             { "new sticky keys state received: $str1" }
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinator.kt b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinator.kt
new file mode 100644
index 0000000..b68551b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinator.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.stickykeys.ui
+
+import android.app.Dialog
+import android.util.Log
+import android.view.Gravity
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import android.view.Window
+import android.view.WindowManager
+import com.android.systemui.compose.ComposeFacade
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyboard.stickykeys.StickyKeysLogger
+import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
+import com.android.systemui.statusbar.phone.SystemUIDialogFactory
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@SysUISingleton
+class StickyKeysIndicatorCoordinator
+@Inject
+constructor(
+    @Application private val applicationScope: CoroutineScope,
+    private val dialogFactory: SystemUIDialogFactory,
+    private val viewModel: StickyKeysIndicatorViewModel,
+    private val stickyKeysLogger: StickyKeysLogger,
+) {
+
+    private var dialog: Dialog? = null
+
+    fun startListening() {
+        // this check needs to be moved to PhysicalKeyboardCoreStartable
+        if (!ComposeFacade.isComposeAvailable()) {
+            Log.e("StickyKeysIndicatorCoordinator", "Compose is required for this UI")
+            return
+        }
+        applicationScope.launch {
+            viewModel.indicatorContent.collect { stickyKeys ->
+                stickyKeysLogger.logNewUiState(stickyKeys)
+                if (stickyKeys.isEmpty()) {
+                    dialog?.dismiss()
+                    dialog = null
+                } else if (dialog == null) {
+                    dialog = ComposeFacade.createStickyKeysDialog(dialogFactory, viewModel).apply {
+                        setCanceledOnTouchOutside(false)
+                        window?.setAttributes()
+                        show()
+                    }
+                }
+            }
+        }
+    }
+
+    private fun Window.setAttributes() {
+        setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL)
+        addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
+        clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND)
+        setGravity(Gravity.TOP or Gravity.END)
+        attributes = WindowManager.LayoutParams().apply {
+            copyFrom(attributes)
+            width = WRAP_CONTENT
+            title = "StickyKeysIndicator"
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinatorTest.kt
new file mode 100644
index 0000000..df73cc8
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/StickyKeysIndicatorCoordinatorTest.kt
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.stickykeys.ui
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.compose.ComposeFacade
+import com.android.systemui.keyboard.data.repository.FakeStickyKeysRepository
+import com.android.systemui.keyboard.data.repository.keyboardRepository
+import com.android.systemui.keyboard.stickykeys.StickyKeysLogger
+import com.android.systemui.keyboard.stickykeys.shared.model.Locked
+import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey.SHIFT
+import com.android.systemui.keyboard.stickykeys.ui.viewmodel.StickyKeysIndicatorViewModel
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.phone.ComponentSystemUIDialog
+import com.android.systemui.statusbar.phone.SystemUIDialogFactory
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.verifyZeroInteractions
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class StickyKeysIndicatorCoordinatorTest : SysuiTestCase() {
+
+    private lateinit var coordinator: StickyKeysIndicatorCoordinator
+    private val testScope = TestScope(StandardTestDispatcher())
+    private val stickyKeysRepository = FakeStickyKeysRepository()
+    private val dialog = mock<ComponentSystemUIDialog>()
+
+    @Before
+    fun setup() {
+        Assume.assumeTrue(ComposeFacade.isComposeAvailable())
+        val dialogFactory = mock<SystemUIDialogFactory> {
+            whenever(applicationContext).thenReturn(context)
+            whenever(create(any(), anyInt(), anyBoolean())).thenReturn(dialog)
+        }
+        val keyboardRepository = Kosmos().keyboardRepository
+        val viewModel = StickyKeysIndicatorViewModel(
+                stickyKeysRepository,
+                keyboardRepository,
+                testScope.backgroundScope)
+        coordinator = StickyKeysIndicatorCoordinator(
+                testScope.backgroundScope,
+                dialogFactory,
+                viewModel,
+                mock<StickyKeysLogger>())
+        coordinator.startListening()
+        keyboardRepository.setIsAnyKeyboardConnected(true)
+    }
+
+    @Test
+    fun dialogIsShownWhenStickyKeysAreEmitted() {
+        testScope.run {
+            verifyZeroInteractions(dialog)
+
+            stickyKeysRepository.setStickyKeys(linkedMapOf(SHIFT to Locked(true)))
+            runCurrent()
+
+            verify(dialog).show()
+        }
+    }
+
+    @Test
+    fun dialogDisappearsWhenStickyKeysAreEmpty() {
+        testScope.run {
+            verifyZeroInteractions(dialog)
+
+            stickyKeysRepository.setStickyKeys(linkedMapOf(SHIFT to Locked(true)))
+            runCurrent()
+            stickyKeysRepository.setStickyKeys(linkedMapOf())
+            runCurrent()
+
+            verify(dialog).dismiss()
+        }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
index d397fc2..8a71368 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/stickykeys/ui/viewmodel/StickyKeysIndicatorViewModelTest.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
@@ -46,6 +47,7 @@
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyZeroInteractions
 
+@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 @RunWith(JUnit4::class)
 class StickyKeysIndicatorViewModelTest : SysuiTestCase() {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeStickyKeysRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeStickyKeysRepository.kt
new file mode 100644
index 0000000..68e1457
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/FakeStickyKeysRepository.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.data.repository
+
+import com.android.systemui.keyboard.stickykeys.data.repository.StickyKeysRepository
+import com.android.systemui.keyboard.stickykeys.shared.model.Locked
+import com.android.systemui.keyboard.stickykeys.shared.model.ModifierKey
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeStickyKeysRepository : StickyKeysRepository {
+    override val settingEnabled: Flow<Boolean> = MutableStateFlow(true)
+    private val _stickyKeys: MutableStateFlow<LinkedHashMap<ModifierKey, Locked>> =
+        MutableStateFlow(LinkedHashMap())
+
+    override val stickyKeys: Flow<LinkedHashMap<ModifierKey, Locked>> = _stickyKeys
+
+    fun setStickyKeys(keys: LinkedHashMap<ModifierKey, Locked>) {
+        _stickyKeys.value = keys
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryKosmos.kt
new file mode 100644
index 0000000..46f7355
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyboard/data/repository/KeyboardRepositoryKosmos.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyboard.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.keyboardRepository by Kosmos.Fixture { FakeKeyboardRepository() }
\ No newline at end of file
diff --git a/services/backup/flags.aconfig b/services/backup/flags.aconfig
index 549fa36..4022e33 100644
--- a/services/backup/flags.aconfig
+++ b/services/backup/flags.aconfig
@@ -10,6 +10,15 @@
 }
 
 flag {
+    name: "enable_metrics_system_backup_agents"
+    namespace: "backup"
+    description: "Enable SystemBackupAgent to collect B&R agent metrics by passing an instance of "
+            "the logger to each BackupHelper."
+    bug: "296844513"
+    is_fixed_read_only: true
+}
+
+flag {
     name: "enable_max_size_writes_to_pipes"
     namespace: "onboarding"
     description: "Enables the write buffer to pipes to be of maximum size."
diff --git a/services/core/Android.bp b/services/core/Android.bp
index fdcd27d..3164e08 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -211,6 +211,7 @@
         "com_android_wm_shell_flags_lib",
         "com.android.server.utils_aconfig-java",
         "service-jobscheduler-deviceidle.flags-aconfig-java",
+        "backup_flags_lib",
         "policy_flags_lib",
     ],
     javac_shard_size: 50,
diff --git a/services/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java
index de4979a..5b9469b 100644
--- a/services/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/services/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -20,7 +20,8 @@
 import android.app.backup.BackupAgentHelper;
 import android.app.backup.BackupAnnotations.BackupDestination;
 import android.app.backup.BackupDataInput;
-import android.app.backup.BackupHelper;
+import android.app.backup.BackupHelperWithLogger;
+import android.app.backup.BackupRestoreEventLogger;
 import android.app.backup.FullBackup;
 import android.app.backup.FullBackupDataOutput;
 import android.app.backup.WallpaperBackupHelper;
@@ -33,9 +34,10 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
-
 import com.google.android.collect.Sets;
 
+import com.android.server.backup.Flags;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.Set;
@@ -107,10 +109,12 @@
 
     private int mUserId = UserHandle.USER_SYSTEM;
     private boolean mIsProfileUser = false;
+    private BackupRestoreEventLogger mLogger;
 
     @Override
     public void onCreate(UserHandle user, @BackupDestination int backupDestination) {
         super.onCreate(user, backupDestination);
+        mLogger = this.getBackupRestoreEventLogger();
 
         mUserId = user.getIdentifier();
         if (mUserId != UserHandle.USER_SYSTEM) {
@@ -209,9 +213,12 @@
         }
     }
 
-    private void addHelperIfEligibleForUser(String keyPrefix, BackupHelper helper) {
+    private void addHelperIfEligibleForUser(String keyPrefix, BackupHelperWithLogger helper) {
         if (isHelperEligibleForUser(keyPrefix)) {
             addHelper(keyPrefix, helper);
+            if (Flags.enableMetricsSystemBackupAgents()) {
+                helper.setLogger(mLogger);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index ac826af..b5346a3 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -1680,9 +1680,8 @@
                             mContext,
                             /* requestCode */ 0,
                             intent,
-                            PendingIntent.FLAG_ONE_SHOT
-                                    | PendingIntent.FLAG_IMMUTABLE
-                                    | PendingIntent.FLAG_CANCEL_CURRENT,
+                            PendingIntent.FLAG_IMMUTABLE
+                                    | FLAG_UPDATE_CURRENT,
                             /* options */ null,
                             user);
             return pi == null ? null : pi.getIntentSender();
diff --git a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
index f0c8437..9c60fbb 100644
--- a/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
+++ b/services/core/java/com/android/server/tv/interactive/TvInteractiveAppManagerService.java
@@ -1038,7 +1038,7 @@
                 }
             } finally {
                 if (surface != null) {
-                    // surface is not used in TvAdManagerService.
+                    // surface is not used in TvInteractiveAppManagerService.
                     surface.release();
                 }
                 Binder.restoreCallingIdentity(identity);
@@ -1106,67 +1106,6 @@
             }
         }
 
-        @Override
-        public void createMediaView(IBinder sessionToken, IBinder windowToken, Rect frame,
-                int userId) {
-            final int callingUid = Binder.getCallingUid();
-            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
-                    userId, "createMediaView");
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                synchronized (mLock) {
-                    try {
-                        getAdSessionLocked(sessionToken, callingUid, resolvedUserId)
-                                .createMediaView(windowToken, frame);
-                    } catch (RemoteException | SessionNotFoundException e) {
-                        Slog.e(TAG, "error in createMediaView", e);
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-
-        @Override
-        public void relayoutMediaView(IBinder sessionToken, Rect frame, int userId) {
-            final int callingUid = Binder.getCallingUid();
-            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
-                    userId, "relayoutMediaView");
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                synchronized (mLock) {
-                    try {
-                        getAdSessionLocked(sessionToken, callingUid, resolvedUserId)
-                                .relayoutMediaView(frame);
-                    } catch (RemoteException | SessionNotFoundException e) {
-                        Slog.e(TAG, "error in relayoutMediaView", e);
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-
-        @Override
-        public void removeMediaView(IBinder sessionToken, int userId) {
-            final int callingUid = Binder.getCallingUid();
-            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
-                    userId, "removeMediaView");
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                synchronized (mLock) {
-                    try {
-                        getAdSessionLocked(sessionToken, callingUid, resolvedUserId)
-                                .removeMediaView();
-                    } catch (RemoteException | SessionNotFoundException e) {
-                        Slog.e(TAG, "error in removeMediaView", e);
-                    }
-                }
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-
     }
 
     private final class BinderService extends ITvInteractiveAppManager.Stub {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3b46c11..036f7b6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -7960,6 +7960,7 @@
         if (mLetterboxUiController.shouldIgnoreRequestedOrientation(requestedOrientation)) {
             return;
         }
+        final int originalRelaunchingCount = mPendingRelaunchCount;
         // This is necessary in order to avoid going into size compat mode when the orientation
         // change request comes from the app
         if (getRequestedConfigurationOrientation(false, requestedOrientation)
@@ -7977,8 +7978,10 @@
         // the request is handled at task level with letterbox.
         if (!getMergedOverrideConfiguration().equals(
                 mLastReportedConfiguration.getMergedConfiguration())) {
-            ensureActivityConfiguration(
-                    false /* ignoreVisibility */, true /* isRequestedOrientationChanged */);
+            ensureActivityConfiguration(false /* ignoreVisibility */);
+            if (mPendingRelaunchCount > originalRelaunchingCount) {
+                mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(true);
+            }
             if (mTransitionController.inPlayingTransition(this)) {
                 mTransitionController.mValidateActivityCompat.add(this);
             }
@@ -9484,11 +9487,6 @@
         return ensureActivityConfiguration(false /* ignoreVisibility */);
     }
 
-    boolean ensureActivityConfiguration(boolean ignoreVisibility) {
-        return ensureActivityConfiguration(ignoreVisibility,
-                false /* isRequestedOrientationChanged */);
-    }
-
     /**
      * Make sure the given activity matches the current configuration. Ensures the HistoryRecord
      * is updated with the correct configuration and all other bookkeeping is handled.
@@ -9497,13 +9495,10 @@
      *                         (stopped state). This is useful for the case where we know the
      *                         activity will be visible soon and we want to ensure its configuration
      *                         before we make it visible.
-     * @param isRequestedOrientationChanged whether this is triggered in response to an app calling
-     *                                      {@link android.app.Activity#setRequestedOrientation}.
      * @return False if the activity was relaunched and true if it wasn't relaunched because we
      *         can't or the app handles the specific configuration that is changing.
      */
-    boolean ensureActivityConfiguration(boolean ignoreVisibility,
-            boolean isRequestedOrientationChanged) {
+    boolean ensureActivityConfiguration(boolean ignoreVisibility) {
         final Task rootTask = getRootTask();
         if (rootTask.mConfigWillChange) {
             ProtoLog.v(WM_DEBUG_CONFIGURATION, "Skipping config check "
@@ -9640,9 +9635,6 @@
             } else {
                 mRelaunchReason = RELAUNCH_REASON_NONE;
             }
-            if (isRequestedOrientationChanged) {
-                mLetterboxUiController.setRelaunchingAfterRequestedOrientationChanged(true);
-            }
             if (mState == PAUSING) {
                 // A little annoying: we are waiting for this activity to finish pausing. Let's not
                 // do anything now, but just flag that it needs to be restarted when done pausing.
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 2bd49bf..a4d15e0 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -19,6 +19,7 @@
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
+import static android.view.View.FOCUS_FORWARD;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.TRANSIT_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
@@ -60,6 +61,7 @@
 import com.android.internal.policy.TransitionAnimation;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.server.wm.utils.InsetUtils;
+import com.android.window.flags.Flags;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -167,6 +169,24 @@
                 return null;
             }
 
+            // Move focus to the adjacent embedded window if it is higher than this window
+            final TaskFragment taskFragment = window.getTaskFragment();
+            final TaskFragment adjacentTaskFragment =
+                    taskFragment != null ? taskFragment.getAdjacentTaskFragment() : null;
+            if (adjacentTaskFragment != null && taskFragment.isEmbedded()
+                    && Flags.embeddedActivityBackNavFlag()) {
+                final WindowContainer parent = taskFragment.getParent();
+                if (parent.mChildren.indexOf(taskFragment) < parent.mChildren.indexOf(
+                        adjacentTaskFragment)) {
+                    mWindowManagerService.moveFocusToAdjacentWindow(window, FOCUS_FORWARD);
+                    window = wmService.getFocusedWindowLocked();
+                    if (window == null) {
+                        Slog.e(TAG, "Adjacent window is null, returning null.");
+                        return null;
+                    }
+                }
+            }
+
             // This is needed to bridge the old and new back behavior with recents.  While in
             // Overview with live tile enabled, the previous app is technically focused but we
             // add an input consumer to capture all input that would otherwise go to the apps
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f8ac8da..9650b8bc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -9156,55 +9156,63 @@
             if (fromWin == null || !fromWin.isFocused()) {
                 return false;
             }
-            final TaskFragment fromFragment = fromWin.getTaskFragment();
-            if (fromFragment == null) {
-                return false;
-            }
-            final TaskFragment adjacentFragment = fromFragment.getAdjacentTaskFragment();
-            if (adjacentFragment == null || adjacentFragment.asTask() != null) {
-                // Don't move the focus to another task.
-                return false;
-            }
-            final Rect fromBounds = fromFragment.getBounds();
-            final Rect adjacentBounds = adjacentFragment.getBounds();
-            switch (direction) {
-                case View.FOCUS_LEFT:
-                    if (adjacentBounds.left >= fromBounds.left) {
-                        return false;
-                    }
-                    break;
-                case View.FOCUS_UP:
-                    if (adjacentBounds.top >= fromBounds.top) {
-                        return false;
-                    }
-                    break;
-                case View.FOCUS_RIGHT:
-                    if (adjacentBounds.right <= fromBounds.right) {
-                        return false;
-                    }
-                    break;
-                case View.FOCUS_DOWN:
-                    if (adjacentBounds.bottom <= fromBounds.bottom) {
-                        return false;
-                    }
-                    break;
-                case View.FOCUS_BACKWARD:
-                case View.FOCUS_FORWARD:
-                    // These are not absolute directions. Skip checking the bounds.
-                    break;
-                default:
+            return moveFocusToAdjacentWindow(fromWin, direction);
+        }
+    }
+
+    boolean moveFocusToAdjacentWindow(WindowState fromWin, @FocusDirection int direction) {
+        final TaskFragment fromFragment = fromWin.getTaskFragment();
+        if (fromFragment == null) {
+            return false;
+        }
+        final TaskFragment adjacentFragment = fromFragment.getAdjacentTaskFragment();
+        if (adjacentFragment == null || adjacentFragment.asTask() != null) {
+            // Don't move the focus to another task.
+            return false;
+        }
+        if (adjacentFragment.isIsolatedNav()) {
+            // Don't move the focus if the adjacent TF is isolated navigation.
+            return false;
+        }
+        final Rect fromBounds = fromFragment.getBounds();
+        final Rect adjacentBounds = adjacentFragment.getBounds();
+        switch (direction) {
+            case View.FOCUS_LEFT:
+                if (adjacentBounds.left >= fromBounds.left) {
                     return false;
-            }
-            final ActivityRecord topRunningActivity = adjacentFragment.topRunningActivity(
-                    true /* focusableOnly */);
-            if (topRunningActivity == null) {
+                }
+                break;
+            case View.FOCUS_UP:
+                if (adjacentBounds.top >= fromBounds.top) {
+                    return false;
+                }
+                break;
+            case View.FOCUS_RIGHT:
+                if (adjacentBounds.right <= fromBounds.right) {
+                    return false;
+                }
+                break;
+            case View.FOCUS_DOWN:
+                if (adjacentBounds.bottom <= fromBounds.bottom) {
+                    return false;
+                }
+                break;
+            case View.FOCUS_BACKWARD:
+            case View.FOCUS_FORWARD:
+                // These are not absolute directions. Skip checking the bounds.
+                break;
+            default:
                 return false;
-            }
-            moveDisplayToTopInternal(topRunningActivity.getDisplayId());
-            handleTaskFocusChange(topRunningActivity.getTask(), topRunningActivity);
-            if (fromWin.isFocused()) {
-                return false;
-            }
+        }
+        final ActivityRecord topRunningActivity = adjacentFragment.topRunningActivity(
+                true /* focusableOnly */);
+        if (topRunningActivity == null) {
+            return false;
+        }
+        moveDisplayToTopInternal(topRunningActivity.getDisplayId());
+        handleTaskFocusChange(topRunningActivity.getTask(), topRunningActivity);
+        if (fromWin.isFocused()) {
+            return false;
         }
         return true;
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java
index 4095be7..18dc114 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/SystemBackupAgentTest.java
@@ -20,11 +20,13 @@
 
 import android.annotation.NonNull;
 import android.app.backup.BackupHelper;
+import android.app.backup.BackupHelperWithLogger;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.util.ArraySet;
 
 import static org.mockito.Mockito.when;
@@ -32,7 +34,10 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
+import com.android.server.backup.Flags;
+
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -55,6 +60,9 @@
     @Mock
     private PackageManager mPackageManagerMock;
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -71,7 +79,7 @@
 
         mSystemBackupAgent.onCreate(userHandle, /* backupDestination= */ 0);
 
-        assertThat(mSystemBackupAgent.mAddedHelpers)
+        assertThat(mSystemBackupAgent.mAddedHelpersKey)
                 .containsExactly(
                         "account_sync_settings",
                         "preferred_activities",
@@ -96,7 +104,7 @@
 
         mSystemBackupAgent.onCreate(userHandle, /* backupDestination= */ 0);
 
-        assertThat(mSystemBackupAgent.mAddedHelpers)
+        assertThat(mSystemBackupAgent.mAddedHelpersKey)
                 .containsExactly(
                         "account_sync_settings",
                         "preferred_activities",
@@ -118,7 +126,7 @@
 
         mSystemBackupAgent.onCreate(userHandle, /* backupDestination= */ 0);
 
-        assertThat(mSystemBackupAgent.mAddedHelpers)
+        assertThat(mSystemBackupAgent.mAddedHelpersKey)
                 .containsExactly(
                         "account_sync_settings",
                         "notifications",
@@ -134,7 +142,7 @@
 
         mSystemBackupAgent.onCreate(userHandle, /* backupDestination= */ 0);
 
-        assertThat(mSystemBackupAgent.mAddedHelpers)
+        assertThat(mSystemBackupAgent.mAddedHelpersKey)
                 .containsExactly(
                         "account_sync_settings",
                         "preferred_activities",
@@ -147,12 +155,42 @@
                         "companion");
     }
 
+    @Test
+    public void onAddHelperIfEligibleForUser_flagIsOff_helpersHaveNoLogger() {
+        UserHandle userHandle = new UserHandle(UserHandle.USER_SYSTEM);
+        when(mUserManagerMock.isProfile()).thenReturn(false);
+        mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_METRICS_SYSTEM_BACKUP_AGENTS);
+
+        mSystemBackupAgent.onCreate(userHandle, /* backupDestination= */ 0);
+
+        for (BackupHelperWithLogger helper:mSystemBackupAgent.mAddedHelpers){
+            assertThat(helper.isLoggerSet()).isFalse();
+        }
+    }
+
+    @Test
+    public void onAddHelperIfEligibleForUser_flagIsOn_helpersHaveLogger() {
+        UserHandle userHandle = new UserHandle(UserHandle.USER_SYSTEM);
+        when(mUserManagerMock.isProfile()).thenReturn(false);
+        mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_METRICS_SYSTEM_BACKUP_AGENTS);
+
+        mSystemBackupAgent.onCreate(userHandle, /* backupDestination= */ 0);
+
+        for (BackupHelperWithLogger helper:mSystemBackupAgent.mAddedHelpers){
+            assertThat(helper.isLoggerSet()).isTrue();
+        }
+    }
+
     private class TestableSystemBackupAgent extends SystemBackupAgent {
-        final Set<String> mAddedHelpers = new ArraySet<>();
+        final Set<String> mAddedHelpersKey = new ArraySet<>();
+        final Set<BackupHelperWithLogger> mAddedHelpers = new ArraySet<>();
 
         @Override
         public void addHelper(String keyPrefix, BackupHelper helper) {
-            mAddedHelpers.add(keyPrefix);
+            mAddedHelpersKey.add(keyPrefix);
+            if (helper instanceof BackupHelperWithLogger) {
+                mAddedHelpers.add((BackupHelperWithLogger) helper);
+            }
         }
 
         @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index 402cbcc..c44be7b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -56,6 +56,7 @@
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
 import android.util.ArraySet;
 import android.view.WindowManager;
 import android.window.BackAnimationAdapter;
@@ -69,6 +70,7 @@
 import android.window.WindowOnBackInvokedDispatcher;
 
 import com.android.server.LocalServices;
+import com.android.window.flags.Flags;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -81,6 +83,12 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+/**
+ * Tests for the {@link BackNavigationController} class.
+ *
+ * Build/Install/Run:
+ *  atest WmTests:BackNavigationControllerTests
+ */
 @Presubmit
 @RunWith(WindowTestRunner.class)
 public class BackNavigationControllerTests extends WindowTestsBase {
@@ -623,6 +631,22 @@
                 0, navigationObserver.getCount());
     }
 
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_EMBEDDED_ACTIVITY_BACK_NAV_FLAG)
+    public void testAdjacentFocusInActivityEmbedding() {
+        Task task = createTask(mDefaultDisplay);
+        TaskFragment primary = createTaskFragmentWithActivity(task);
+        TaskFragment secondary = createTaskFragmentWithActivity(task);
+        primary.setAdjacentTaskFragment(secondary);
+        secondary.setAdjacentTaskFragment(primary);
+
+        WindowState windowState = mock(WindowState.class);
+        doReturn(windowState).when(mWm).getFocusedWindowLocked();
+        doReturn(primary).when(windowState).getTaskFragment();
+
+        startBackNavigation();
+        verify(mWm).moveFocusToAdjacentWindow(any(), anyInt());
+    }
 
     /**
      * Test with
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 782d89c..95850ac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -2131,8 +2131,8 @@
         // Once transition starts, rotation is applied and transition shows DC rotating.
         testPlayer.startTransition();
         waitUntilHandlersIdle();
-        verify(activity1).ensureActivityConfiguration(anyBoolean(), anyBoolean());
-        verify(activity2).ensureActivityConfiguration(anyBoolean(), anyBoolean());
+        verify(activity1).ensureActivityConfiguration(anyBoolean());
+        verify(activity2).ensureActivityConfiguration(anyBoolean());
         assertNotEquals(origRot, dc.getConfiguration().windowConfiguration.getRotation());
         assertNotNull(testPlayer.mLastReady);
         assertTrue(testPlayer.mController.isPlaying());
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 7f554f3..6759eef 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -1024,8 +1024,17 @@
         // Activity is sandboxed due to fixed aspect ratio.
         assertActivityMaxBoundsSandboxed();
 
+        // Prepare the states for verifying relaunching after changing orientation.
+        mActivity.finishRelaunching();
+        mActivity.setState(RESUMED, "testFixedAspectRatioOrientationChangeOrientation");
+        mActivity.setLastReportedConfiguration(mAtm.getGlobalConfiguration(),
+                mActivity.getConfiguration());
+
         // Change the fixed orientation.
         mActivity.setRequestedOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+        assertTrue(mActivity.isRelaunching());
+        assertTrue(mActivity.mLetterboxUiController
+                .getIsRelaunchingAfterRequestedOrientationChanged());
 
         assertFitted();
         assertEquals(originalBounds.width(), mActivity.getBounds().height());