Merge changes from topic "AppOpPermissionAppListTest"

* changes:
  Refactor TogglePermissionAppInfoPageProvider
  Hide not changeable app from AppOpPermissionAppList
  Add tests for Flows & StateFlowBridge
diff --git a/core/java/android/window/SnapshotDrawerUtils.java b/core/java/android/window/SnapshotDrawerUtils.java
new file mode 100644
index 0000000..1a58fd5
--- /dev/null
+++ b/core/java/android/window/SnapshotDrawerUtils.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2022 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.window;
+
+import static android.graphics.Color.WHITE;
+import static android.graphics.Color.alpha;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
+import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
+
+import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.getNavigationBarRect;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityThread;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.hardware.HardwareBuffer;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.DecorView;
+
+/**
+ * Utils class to help draw a snapshot on a surface.
+ * @hide
+ */
+public class SnapshotDrawerUtils {
+    private static final String TAG = "SnapshotDrawerUtils";
+
+    /**
+     * When creating the starting window, we use the exact same layout flags such that we end up
+     * with a window with the exact same dimensions etc. However, these flags are not used in layout
+     * and might cause other side effects so we exclude them.
+     */
+    static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
+            | FLAG_NOT_TOUCHABLE
+            | FLAG_NOT_TOUCH_MODAL
+            | FLAG_ALT_FOCUSABLE_IM
+            | FLAG_NOT_FOCUSABLE
+            | FLAG_HARDWARE_ACCELERATED
+            | FLAG_IGNORE_CHEEK_PRESSES
+            | FLAG_LOCAL_FOCUS_MODE
+            | FLAG_SLIPPERY
+            | FLAG_WATCH_OUTSIDE_TOUCH
+            | FLAG_SPLIT_TOUCH
+            | FLAG_SCALED
+            | FLAG_SECURE;
+
+    private static final RectF sTmpSnapshotSize = new RectF();
+    private static final RectF sTmpDstFrame = new RectF();
+
+    private static final Matrix sSnapshotMatrix = new Matrix();
+    private static final float[] sTmpFloat9 = new float[9];
+    private static final Paint sBackgroundPaint = new Paint();
+
+    /**
+     * The internal object to hold the surface and drawing on it.
+     */
+    @VisibleForTesting
+    public static class SnapshotSurface {
+        private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+        private final SurfaceControl mRootSurface;
+        private final TaskSnapshot mSnapshot;
+        private final CharSequence mTitle;
+
+        private SystemBarBackgroundPainter mSystemBarBackgroundPainter;
+        private final Rect mTaskBounds;
+        private final Rect mFrame = new Rect();
+        private final Rect mSystemBarInsets = new Rect();
+        private boolean mSizeMismatch;
+
+        public SnapshotSurface(SurfaceControl rootSurface, TaskSnapshot snapshot,
+                CharSequence title,
+                Rect taskBounds) {
+            mRootSurface = rootSurface;
+            mSnapshot = snapshot;
+            mTitle = title;
+            mTaskBounds = taskBounds;
+        }
+
+        /**
+         * Initiate system bar painter to draw the system bar background.
+         */
+        void initiateSystemBarPainter(int windowFlags, int windowPrivateFlags,
+                int appearance, ActivityManager.TaskDescription taskDescription,
+                @WindowInsets.Type.InsetsType int requestedVisibleTypes) {
+            mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
+                    windowPrivateFlags, appearance, taskDescription, 1f, requestedVisibleTypes);
+            int backgroundColor = taskDescription.getBackgroundColor();
+            sBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
+        }
+
+        /**
+         * Set frame size.
+         */
+        void setFrames(Rect frame, Rect systemBarInsets) {
+            mFrame.set(frame);
+            mSystemBarInsets.set(systemBarInsets);
+            final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+            mSizeMismatch = (mFrame.width() != snapshot.getWidth()
+                    || mFrame.height() != snapshot.getHeight());
+            mSystemBarBackgroundPainter.setInsets(systemBarInsets);
+        }
+
+        private void drawSnapshot(boolean releaseAfterDraw) {
+            Log.v(TAG, "Drawing snapshot surface sizeMismatch=" + mSizeMismatch);
+            if (mSizeMismatch) {
+                // The dimensions of the buffer and the window don't match, so attaching the buffer
+                // will fail. Better create a child window with the exact dimensions and fill the
+                // parent window with the background color!
+                drawSizeMismatchSnapshot();
+            } else {
+                drawSizeMatchSnapshot();
+            }
+
+            // In case window manager leaks us, make sure we don't retain the snapshot.
+            if (mSnapshot.getHardwareBuffer() != null) {
+                mSnapshot.getHardwareBuffer().close();
+            }
+            if (releaseAfterDraw) {
+                mRootSurface.release();
+            }
+        }
+
+        private void drawSizeMatchSnapshot() {
+            mTransaction.setBuffer(mRootSurface, mSnapshot.getHardwareBuffer())
+                    .setColorSpace(mRootSurface, mSnapshot.getColorSpace())
+                    .apply();
+        }
+
+        private void drawSizeMismatchSnapshot() {
+            final HardwareBuffer buffer = mSnapshot.getHardwareBuffer();
+            final SurfaceSession session = new SurfaceSession();
+
+            // We consider nearly matched dimensions as there can be rounding errors and the user
+            // won't notice very minute differences from scaling one dimension more than the other
+            final boolean aspectRatioMismatch = !isAspectRatioMatch(mFrame, mSnapshot);
+
+            // Keep a reference to it such that it doesn't get destroyed when finalized.
+            SurfaceControl childSurfaceControl = new SurfaceControl.Builder(session)
+                    .setName(mTitle + " - task-snapshot-surface")
+                    .setBLASTLayer()
+                    .setFormat(buffer.getFormat())
+                    .setParent(mRootSurface)
+                    .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot")
+                    .build();
+
+            final Rect frame;
+            // We can just show the surface here as it will still be hidden as the parent is
+            // still hidden.
+            mTransaction.show(childSurfaceControl);
+            if (aspectRatioMismatch) {
+                // Clip off ugly navigation bar.
+                final Rect crop = calculateSnapshotCrop();
+                frame = calculateSnapshotFrame(crop);
+                mTransaction.setWindowCrop(childSurfaceControl, crop);
+                mTransaction.setPosition(childSurfaceControl, frame.left, frame.top);
+                sTmpSnapshotSize.set(crop);
+                sTmpDstFrame.set(frame);
+            } else {
+                frame = null;
+                sTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
+                sTmpDstFrame.set(mFrame);
+                sTmpDstFrame.offsetTo(0, 0);
+            }
+
+            // Scale the mismatch dimensions to fill the task bounds
+            sSnapshotMatrix.setRectToRect(sTmpSnapshotSize, sTmpDstFrame, Matrix.ScaleToFit.FILL);
+            mTransaction.setMatrix(childSurfaceControl, sSnapshotMatrix, sTmpFloat9);
+            mTransaction.setColorSpace(childSurfaceControl, mSnapshot.getColorSpace());
+            mTransaction.setBuffer(childSurfaceControl, mSnapshot.getHardwareBuffer());
+
+            if (aspectRatioMismatch) {
+                GraphicBuffer background = GraphicBuffer.create(mFrame.width(), mFrame.height(),
+                        PixelFormat.RGBA_8888,
+                        GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_HW_COMPOSER
+                                | GraphicBuffer.USAGE_SW_WRITE_RARELY);
+                // TODO: Support this on HardwareBuffer
+                final Canvas c = background.lockCanvas();
+                drawBackgroundAndBars(c, frame);
+                background.unlockCanvasAndPost(c);
+                mTransaction.setBuffer(mRootSurface,
+                        HardwareBuffer.createFromGraphicBuffer(background));
+            }
+            mTransaction.apply();
+            childSurfaceControl.release();
+        }
+
+        /**
+         * Calculates the snapshot crop in snapshot coordinate space.
+         *
+         * @return crop rect in snapshot coordinate space.
+         */
+        Rect calculateSnapshotCrop() {
+            final Rect rect = new Rect();
+            final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+            rect.set(0, 0, snapshot.getWidth(), snapshot.getHeight());
+            final Rect insets = mSnapshot.getContentInsets();
+
+            final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
+            final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
+
+            // Let's remove all system decorations except the status bar, but only if the task is at
+            // the very top of the screen.
+            final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
+            rect.inset((int) (insets.left * scaleX),
+                    isTop ? 0 : (int) (insets.top * scaleY),
+                    (int) (insets.right * scaleX),
+                    (int) (insets.bottom * scaleY));
+            return rect;
+        }
+
+        /**
+         * Calculates the snapshot frame in window coordinate space from crop.
+         *
+         * @param crop rect that is in snapshot coordinate space.
+         */
+        Rect calculateSnapshotFrame(Rect crop) {
+            final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+            final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
+            final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
+
+            // Rescale the frame from snapshot to window coordinate space
+            final Rect frame = new Rect(0, 0,
+                    (int) (crop.width() / scaleX + 0.5f),
+                    (int) (crop.height() / scaleY + 0.5f)
+            );
+
+            // However, we also need to make space for the navigation bar on the left side.
+            frame.offset(mSystemBarInsets.left, 0);
+            return frame;
+        }
+
+        /**
+         * Draw status bar and navigation bar background.
+         */
+        void drawBackgroundAndBars(Canvas c, Rect frame) {
+            final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
+            final boolean fillHorizontally = c.getWidth() > frame.right;
+            final boolean fillVertically = c.getHeight() > frame.bottom;
+            if (fillHorizontally) {
+                c.drawRect(frame.right, alpha(mSystemBarBackgroundPainter.mStatusBarColor) == 0xFF
+                        ? statusBarHeight : 0, c.getWidth(), fillVertically
+                        ? frame.bottom : c.getHeight(), sBackgroundPaint);
+            }
+            if (fillVertically) {
+                c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), sBackgroundPaint);
+            }
+            mSystemBarBackgroundPainter.drawDecors(c, frame);
+        }
+
+        /**
+         * Ask system bar background painter to draw status bar background.
+         *
+         */
+        void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+            mSystemBarBackgroundPainter.drawStatusBarBackground(c, alreadyDrawnFrame,
+                    mSystemBarBackgroundPainter.getStatusBarColorViewHeight());
+        }
+
+        /**
+         * Ask system bar background painter to draw navigation bar background.
+         *
+         */
+        void drawNavigationBarBackground(Canvas c) {
+            mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
+        }
+    }
+
+    /**
+     * @return true if the aspect ratio match between a frame and a snapshot buffer.
+     */
+    public static boolean isAspectRatioMatch(Rect frame, TaskSnapshot snapshot) {
+        if (frame.isEmpty()) {
+            return false;
+        }
+        final HardwareBuffer buffer = snapshot.getHardwareBuffer();
+        return Math.abs(
+                ((float) buffer.getWidth() / buffer.getHeight())
+                        - ((float) frame.width() / frame.height())) <= 0.01f;
+    }
+
+    /**
+     * Help method to draw the snapshot on a surface.
+     */
+    public static void drawSnapshotOnSurface(StartingWindowInfo info, WindowManager.LayoutParams lp,
+            SurfaceControl rootSurface, TaskSnapshot snapshot,
+            Rect configBounds, Rect windowBounds, InsetsState topWindowInsetsState,
+            boolean releaseAfterDraw) {
+        if (windowBounds.isEmpty()) {
+            Log.e(TAG, "Unable to draw snapshot on an empty windowBounds");
+            return;
+        }
+        final SnapshotSurface drawSurface = new SnapshotSurface(
+                rootSurface, snapshot, lp.getTitle(), configBounds);
+
+        final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams;
+        final ActivityManager.RunningTaskInfo runningTaskInfo = info.taskInfo;
+        final ActivityManager.TaskDescription taskDescription;
+        if (runningTaskInfo.taskDescription != null) {
+            taskDescription = runningTaskInfo.taskDescription;
+        } else {
+            taskDescription = new ActivityManager.TaskDescription();
+            taskDescription.setBackgroundColor(WHITE);
+        }
+        drawSurface.initiateSystemBarPainter(lp.flags, lp.privateFlags,
+                attrs.insetsFlags.appearance, taskDescription, info.requestedVisibleTypes);
+        final Rect systemBarInsets = getSystemBarInsets(windowBounds, topWindowInsetsState);
+        drawSurface.setFrames(windowBounds, systemBarInsets);
+        drawSurface.drawSnapshot(releaseAfterDraw);
+    }
+
+    /**
+     * Help method to create a layout parameters for a window.
+     */
+    public static WindowManager.LayoutParams createLayoutParameters(StartingWindowInfo info,
+            CharSequence title, @WindowManager.LayoutParams.WindowType int windowType,
+            int pixelFormat, IBinder token) {
+        final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams;
+        final WindowManager.LayoutParams mainWindowParams = info.mainWindowLayoutParams;
+        final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState;
+        if (attrs == null || mainWindowParams == null || topWindowInsetsState == null) {
+            Log.w(TAG, "unable to create taskSnapshot surface ");
+            return null;
+        }
+        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+
+        final int appearance = attrs.insetsFlags.appearance;
+        final int windowFlags = attrs.flags;
+        final int windowPrivateFlags = attrs.privateFlags;
+
+        layoutParams.packageName = mainWindowParams.packageName;
+        layoutParams.windowAnimations = mainWindowParams.windowAnimations;
+        layoutParams.dimAmount = mainWindowParams.dimAmount;
+        layoutParams.type = windowType;
+        layoutParams.format = pixelFormat;
+        layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
+                | FLAG_NOT_FOCUSABLE
+                | FLAG_NOT_TOUCHABLE;
+        // Setting as trusted overlay to let touches pass through. This is safe because this
+        // window is controlled by the system.
+        layoutParams.privateFlags = (windowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS)
+                | PRIVATE_FLAG_TRUSTED_OVERLAY | PRIVATE_FLAG_USE_BLAST;
+        layoutParams.token = token;
+        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+        layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+        layoutParams.insetsFlags.appearance = appearance;
+        layoutParams.insetsFlags.behavior = attrs.insetsFlags.behavior;
+        layoutParams.layoutInDisplayCutoutMode = attrs.layoutInDisplayCutoutMode;
+        layoutParams.setFitInsetsTypes(attrs.getFitInsetsTypes());
+        layoutParams.setFitInsetsSides(attrs.getFitInsetsSides());
+        layoutParams.setFitInsetsIgnoringVisibility(attrs.isFitInsetsIgnoringVisibility());
+
+        layoutParams.setTitle(title);
+        return layoutParams;
+    }
+
+    static Rect getSystemBarInsets(Rect frame, InsetsState state) {
+        return state.calculateInsets(frame, WindowInsets.Type.systemBars(),
+                false /* ignoreVisibility */).toRect();
+    }
+
+    /**
+     * Helper class to draw the background of the system bars in regions the task snapshot isn't
+     * filling the window.
+     */
+    public static class SystemBarBackgroundPainter {
+        private final Paint mStatusBarPaint = new Paint();
+        private final Paint mNavigationBarPaint = new Paint();
+        private final int mStatusBarColor;
+        private final int mNavigationBarColor;
+        private final int mWindowFlags;
+        private final int mWindowPrivateFlags;
+        private final float mScale;
+        private final @WindowInsets.Type.InsetsType int mRequestedVisibleTypes;
+        private final Rect mSystemBarInsets = new Rect();
+
+        public SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int appearance,
+                ActivityManager.TaskDescription taskDescription, float scale,
+                @WindowInsets.Type.InsetsType int requestedVisibleTypes) {
+            mWindowFlags = windowFlags;
+            mWindowPrivateFlags = windowPrivateFlags;
+            mScale = scale;
+            final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
+            final int semiTransparent = context.getColor(
+                    R.color.system_bar_background_semi_transparent);
+            mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
+                    semiTransparent, taskDescription.getStatusBarColor(), appearance,
+                    APPEARANCE_LIGHT_STATUS_BARS,
+                    taskDescription.getEnsureStatusBarContrastWhenTransparent());
+            mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
+                    FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
+                    taskDescription.getNavigationBarColor(), appearance,
+                    APPEARANCE_LIGHT_NAVIGATION_BARS,
+                    taskDescription.getEnsureNavigationBarContrastWhenTransparent()
+                            && context.getResources().getBoolean(
+                            R.bool.config_navBarNeedsScrim));
+            mStatusBarPaint.setColor(mStatusBarColor);
+            mNavigationBarPaint.setColor(mNavigationBarColor);
+            mRequestedVisibleTypes = requestedVisibleTypes;
+        }
+
+        /**
+         * Set system bar insets.
+         */
+        public void setInsets(Rect systemBarInsets) {
+            mSystemBarInsets.set(systemBarInsets);
+        }
+
+        int getStatusBarColorViewHeight() {
+            final boolean forceBarBackground =
+                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
+            if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                    mRequestedVisibleTypes, mStatusBarColor, mWindowFlags,
+                    forceBarBackground)) {
+                return (int) (mSystemBarInsets.top * mScale);
+            } else {
+                return 0;
+            }
+        }
+
+        private boolean isNavigationBarColorViewVisible() {
+            final boolean forceBarBackground =
+                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
+            return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                    mRequestedVisibleTypes, mNavigationBarColor, mWindowFlags,
+                    forceBarBackground);
+        }
+
+        /**
+         * Draw bar colors to a canvas.
+         */
+        public void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+            drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
+            drawNavigationBarBackground(c);
+        }
+
+        void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
+                int statusBarHeight) {
+            if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
+                    && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
+                final int rightInset = (int) (mSystemBarInsets.right * mScale);
+                final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
+                c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight,
+                        mStatusBarPaint);
+            }
+        }
+
+        void drawNavigationBarBackground(Canvas c) {
+            final Rect navigationBarRect = new Rect();
+            getNavigationBarRect(c.getWidth(), c.getHeight(), mSystemBarInsets, navigationBarRect,
+                    mScale);
+            final boolean visible = isNavigationBarColorViewVisible();
+            if (visible && Color.alpha(mNavigationBarColor) != 0
+                    && !navigationBarRect.isEmpty()) {
+                c.drawRect(navigationBarRect, mNavigationBarPaint);
+            }
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java
similarity index 66%
rename from libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
rename to core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java
index 004df2a2..281d677 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
+++ b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2022 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.
@@ -14,22 +14,20 @@
  * limitations under the License.
  */
 
-package com.android.wm.shell.startingsurface;
+package android.window;
 
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager.TaskDescription;
 import android.content.ComponentName;
@@ -42,33 +40,28 @@
 import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.WindowInsets;
-import android.window.TaskSnapshot;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.TestShellExecutor;
-
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
 /**
- * Test class for {@link TaskSnapshotWindow}.
- *
+ * Test class for {@link SnapshotDrawerUtils}.
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class TaskSnapshotWindowTest extends ShellTestCase {
+public class SnapshotDrawerUtilsTest {
 
-    private TaskSnapshotWindow mWindow;
+    private SnapshotDrawerUtils.SnapshotSurface mSnapshotSurface;
 
     private void setupSurface(int width, int height) {
-        setupSurface(width, height, new Rect(), 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+        setupSurface(width, height, new Rect(), FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                 new Rect(0, 0, width, height));
     }
 
-    private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis,
+    private void setupSurface(int width, int height, Rect contentInsets,
             int windowFlags, Rect taskBounds) {
         // Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic
         // this behavior set the taskSize to be the same as the taskBounds width and height. The
@@ -80,12 +73,13 @@
         Point taskSize = new Point(taskBounds.width(), taskBounds.height());
 
         final TaskSnapshot snapshot = createTaskSnapshot(width, height, taskSize, contentInsets);
-        mWindow = new TaskSnapshotWindow(new SurfaceControl(), snapshot, "Test",
-                createTaskDescription(Color.WHITE, Color.RED, Color.BLUE),
-                0 /* appearance */, windowFlags /* windowFlags */, 0 /* privateWindowFlags */,
-                taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD,
-                WindowInsets.Type.defaultVisible(), null /* clearWindow */,
-                new TestShellExecutor());
+        TaskDescription taskDescription = createTaskDescription(Color.WHITE,
+                Color.RED, Color.BLUE);
+
+        mSnapshotSurface = new SnapshotDrawerUtils.SnapshotSurface(
+                new SurfaceControl(), snapshot, "Test", taskBounds);
+        mSnapshotSurface.initiateSystemBarPainter(windowFlags, 0, 0,
+                taskDescription, WindowInsets.Type.defaultVisible());
     }
 
     private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
@@ -101,8 +95,8 @@
                 0 /* systemUiVisibility */, false /* isTranslucent */, false /* hasImeSurface */);
     }
 
-    private static TaskDescription createTaskDescription(int background, int statusBar,
-            int navigationBar) {
+    private static TaskDescription createTaskDescription(int background,
+            int statusBar, int navigationBar) {
         final TaskDescription td = new TaskDescription();
         td.setBackgroundColor(background);
         td.setStatusBarColor(statusBar);
@@ -116,7 +110,7 @@
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(200);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200));
+        mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200));
         verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
     }
 
@@ -126,7 +120,7 @@
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(200);
-        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100));
+        mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100));
         verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(100.0f), eq(200.0f), any());
     }
 
@@ -136,7 +130,7 @@
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(200);
         when(mockCanvas.getHeight()).thenReturn(200);
-        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+        mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
         verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
         verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(200.0f), eq(200.0f), any());
     }
@@ -147,7 +141,7 @@
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+        mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
         verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
     }
 
@@ -157,76 +151,76 @@
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200));
+        mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200));
         verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
     }
 
     @Test
     public void testCalculateSnapshotCrop() {
-        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 0, 100, 100));
-        assertEquals(new Rect(0, 0, 100, 90), mWindow.calculateSnapshotCrop());
+        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(0, 0, 100, 90), mSnapshotSurface.calculateSnapshotCrop());
     }
 
     @Test
     public void testCalculateSnapshotCrop_taskNotOnTop() {
-        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 150));
-        assertEquals(new Rect(0, 10, 100, 90), mWindow.calculateSnapshotCrop());
+        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, new Rect(0, 50, 100, 150));
+        assertEquals(new Rect(0, 10, 100, 90), mSnapshotSurface.calculateSnapshotCrop());
     }
 
     @Test
     public void testCalculateSnapshotCrop_navBarLeft() {
-        setupSurface(100, 100, new Rect(10, 10, 0, 0), 0, 0, new Rect(0, 0, 100, 100));
-        assertEquals(new Rect(10, 0, 100, 100), mWindow.calculateSnapshotCrop());
+        setupSurface(100, 100, new Rect(10, 10, 0, 0), 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(10, 0, 100, 100), mSnapshotSurface.calculateSnapshotCrop());
     }
 
     @Test
     public void testCalculateSnapshotCrop_navBarRight() {
-        setupSurface(100, 100, new Rect(0, 10, 10, 0), 0, 0, new Rect(0, 0, 100, 100));
-        assertEquals(new Rect(0, 0, 90, 100), mWindow.calculateSnapshotCrop());
+        setupSurface(100, 100, new Rect(0, 10, 10, 0), 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(0, 0, 90, 100), mSnapshotSurface.calculateSnapshotCrop());
     }
 
     @Test
     public void testCalculateSnapshotCrop_waterfall() {
-        setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, 0, new Rect(0, 0, 100, 100));
-        assertEquals(new Rect(5, 0, 95, 90), mWindow.calculateSnapshotCrop());
+        setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(5, 0, 95, 90), mSnapshotSurface.calculateSnapshotCrop());
     }
 
     @Test
     public void testCalculateSnapshotFrame() {
         setupSurface(100, 100);
         final Rect insets = new Rect(0, 10, 0, 10);
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         assertEquals(new Rect(0, 0, 100, 80),
-                mWindow.calculateSnapshotFrame(new Rect(0, 10, 100, 90)));
+                mSnapshotSurface.calculateSnapshotFrame(new Rect(0, 10, 100, 90)));
     }
 
     @Test
     public void testCalculateSnapshotFrame_navBarLeft() {
         setupSurface(100, 100);
         final Rect insets = new Rect(10, 10, 0, 0);
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         assertEquals(new Rect(10, 0, 100, 90),
-                mWindow.calculateSnapshotFrame(new Rect(10, 10, 100, 100)));
+                mSnapshotSurface.calculateSnapshotFrame(new Rect(10, 10, 100, 100)));
     }
 
     @Test
     public void testCalculateSnapshotFrame_waterfall() {
-        setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, 0, new Rect(0, 0, 100, 100));
+        setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, new Rect(0, 0, 100, 100));
         final Rect insets = new Rect(0, 10, 0, 10);
-        mWindow.setFrames(new Rect(5, 0, 95, 100), insets);
+        mSnapshotSurface.setFrames(new Rect(5, 0, 95, 100), insets);
         assertEquals(new Rect(0, 0, 90, 90),
-                mWindow.calculateSnapshotFrame(new Rect(5, 0, 95, 90)));
+                mSnapshotSurface.calculateSnapshotFrame(new Rect(5, 0, 95, 90)));
     }
 
     @Test
     public void testDrawStatusBarBackground() {
         setupSurface(100, 100);
         final Rect insets = new Rect(0, 10, 10, 0);
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100));
+        mSnapshotSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100));
         verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
     }
 
@@ -234,11 +228,11 @@
     public void testDrawStatusBarBackground_nullFrame() {
         setupSurface(100, 100);
         final Rect insets = new Rect(0, 10, 10, 0);
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawStatusBarBackground(mockCanvas, null);
+        mSnapshotSurface.drawStatusBarBackground(mockCanvas, null);
         verify(mockCanvas).drawRect(eq(0.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
     }
 
@@ -246,50 +240,50 @@
     public void testDrawStatusBarBackground_nope() {
         setupSurface(100, 100);
         final Rect insets = new Rect(0, 10, 10, 0);
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100));
+        mSnapshotSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100));
         verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
     }
 
     @Test
     public void testDrawNavigationBarBackground() {
         final Rect insets = new Rect(0, 10, 0, 10);
-        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+        setupSurface(100, 100, insets, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                 new Rect(0, 0, 100, 100));
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawNavigationBarBackground(mockCanvas);
+        mSnapshotSurface.drawNavigationBarBackground(mockCanvas);
         verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
     }
 
     @Test
     public void testDrawNavigationBarBackground_left() {
         final Rect insets = new Rect(10, 10, 0, 0);
-        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+        setupSurface(100, 100, insets, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                 new Rect(0, 0, 100, 100));
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawNavigationBarBackground(mockCanvas);
+        mSnapshotSurface.drawNavigationBarBackground(mockCanvas);
         verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
     }
 
     @Test
     public void testDrawNavigationBarBackground_right() {
         final Rect insets = new Rect(0, 10, 10, 0);
-        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+        setupSurface(100, 100, insets, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
                 new Rect(0, 0, 100, 100));
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
         final Canvas mockCanvas = mock(Canvas.class);
         when(mockCanvas.getWidth()).thenReturn(100);
         when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawNavigationBarBackground(mockCanvas);
+        mSnapshotSurface.drawNavigationBarBackground(mockCanvas);
         verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 6ce981e..0a2027f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -16,8 +16,10 @@
 
 package com.android.wm.shell.startingsurface;
 
+import static android.content.Context.CONTEXT_RESTRICTED;
 import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN;
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SOLID_COLOR_SPLASH_SCREEN;
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
@@ -29,6 +31,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -48,9 +51,11 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
+import android.hardware.display.DisplayManager;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -58,7 +63,9 @@
 import android.util.DisplayMetrics;
 import android.util.Slog;
 import android.view.ContextThemeWrapper;
+import android.view.Display;
 import android.view.SurfaceControl;
+import android.view.WindowManager;
 import android.window.SplashScreenView;
 import android.window.StartingWindowInfo;
 import android.window.StartingWindowInfo.StartingWindowType;
@@ -134,6 +141,144 @@
     }
 
     /**
+     * Help method to create a layout parameters for a window.
+     */
+    static Context createContext(Context initContext, StartingWindowInfo windowInfo,
+            int theme, @StartingWindowInfo.StartingWindowType int suggestType,
+            DisplayManager displayManager) {
+        final ActivityManager.RunningTaskInfo taskInfo = windowInfo.taskInfo;
+        final ActivityInfo activityInfo = windowInfo.targetActivityInfo != null
+                ? windowInfo.targetActivityInfo
+                : taskInfo.topActivityInfo;
+        if (activityInfo == null || activityInfo.packageName == null) {
+            return null;
+        }
+
+        final int displayId = taskInfo.displayId;
+        final int taskId = taskInfo.taskId;
+
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
+                "addSplashScreen for package: %s with theme: %s for task: %d, suggestType: %d",
+                activityInfo.packageName, Integer.toHexString(theme), taskId, suggestType);
+        final Display display = displayManager.getDisplay(displayId);
+        if (display == null) {
+            // Can't show splash screen on requested display, so skip showing at all.
+            return null;
+        }
+        Context context = displayId == DEFAULT_DISPLAY
+                ? initContext : initContext.createDisplayContext(display);
+        if (context == null) {
+            return null;
+        }
+        if (theme != context.getThemeResId()) {
+            try {
+                context = context.createPackageContextAsUser(activityInfo.packageName,
+                        CONTEXT_RESTRICTED, UserHandle.of(taskInfo.userId));
+                context.setTheme(theme);
+            } catch (PackageManager.NameNotFoundException e) {
+                Slog.w(TAG, "Failed creating package context with package name "
+                        + activityInfo.packageName + " for user " + taskInfo.userId, e);
+                return null;
+            }
+        }
+
+        final Configuration taskConfig = taskInfo.getConfiguration();
+        if (taskConfig.diffPublicOnly(context.getResources().getConfiguration()) != 0) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
+                    "addSplashScreen: creating context based on task Configuration %s",
+                    taskConfig);
+            final Context overrideContext = context.createConfigurationContext(taskConfig);
+            overrideContext.setTheme(theme);
+            final TypedArray typedArray = overrideContext.obtainStyledAttributes(
+                    com.android.internal.R.styleable.Window);
+            final int resId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0);
+            try {
+                if (resId != 0 && overrideContext.getDrawable(resId) != null) {
+                    // We want to use the windowBackground for the override context if it is
+                    // available, otherwise we use the default one to make sure a themed starting
+                    // window is displayed for the app.
+                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
+                            "addSplashScreen: apply overrideConfig %s",
+                            taskConfig);
+                    context = overrideContext;
+                }
+            } catch (Resources.NotFoundException e) {
+                Slog.w(TAG, "failed creating starting window for overrideConfig at taskId: "
+                        + taskId, e);
+                return null;
+            }
+            typedArray.recycle();
+        }
+        return context;
+    }
+
+    /**
+     * Creates the window layout parameters for splashscreen window.
+     */
+    static WindowManager.LayoutParams createLayoutParameters(Context context,
+            StartingWindowInfo windowInfo,
+            @StartingWindowInfo.StartingWindowType int suggestType,
+            CharSequence title, int pixelFormat, IBinder appToken) {
+        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
+        params.setFitInsetsSides(0);
+        params.setFitInsetsTypes(0);
+        params.format = pixelFormat;
+        int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+        final TypedArray a = context.obtainStyledAttributes(R.styleable.Window);
+        if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
+            windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+        }
+        if (suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
+            if (a.getBoolean(R.styleable.Window_windowDrawsSystemBarBackgrounds, false)) {
+                windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+            }
+        } else {
+            windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        }
+        params.layoutInDisplayCutoutMode = a.getInt(
+                R.styleable.Window_windowLayoutInDisplayCutoutMode,
+                params.layoutInDisplayCutoutMode);
+        params.windowAnimations = a.getResourceId(R.styleable.Window_windowAnimationStyle, 0);
+        a.recycle();
+
+        final ActivityManager.RunningTaskInfo taskInfo = windowInfo.taskInfo;
+        final ActivityInfo activityInfo = windowInfo.targetActivityInfo != null
+                ? windowInfo.targetActivityInfo
+                : taskInfo.topActivityInfo;
+        final int displayId = taskInfo.displayId;
+        // Assumes it's safe to show starting windows of launched apps while
+        // the keyguard is being hidden. This is okay because starting windows never show
+        // secret information.
+        // TODO(b/113840485): Occluded may not only happen on default display
+        if (displayId == DEFAULT_DISPLAY && windowInfo.isKeyguardOccluded) {
+            windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+        }
+
+        // Force the window flags: this is a fake window, so it is not really
+        // touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM
+        // flag because we do know that the next window will take input
+        // focus, so we want to get the IME window up on top of us right away.
+        // Touches will only pass through to the host activity window and will be blocked from
+        // passing to any other windows.
+        windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        params.flags = windowFlags;
+        params.token = appToken;
+        params.packageName = activityInfo.packageName;
+        params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+
+        if (!context.getResources().getCompatibilityInfo().supportsScreen()) {
+            params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+        }
+
+        params.setTitle("Splash Screen " + title);
+        return params;
+    }
+    /**
      * Create a SplashScreenView object.
      *
      * In order to speed up the splash screen view to show on first frame, preparing the
@@ -248,6 +393,26 @@
         return null;
     }
 
+    /**
+     * Creates a SplashScreenView without read animatable icon and branding image.
+     */
+    SplashScreenView makeSimpleSplashScreenContentView(Context context,
+            StartingWindowInfo info, int themeBGColor) {
+        updateDensity();
+        mTmpAttrs.reset();
+        final ActivityInfo ai = info.targetActivityInfo != null
+                ? info.targetActivityInfo
+                : info.taskInfo.topActivityInfo;
+
+        final SplashViewBuilder builder = new SplashViewBuilder(context, ai);
+        final SplashScreenView view = builder
+                .setWindowBGColor(themeBGColor)
+                .chooseStyle(STARTING_WINDOW_TYPE_SPLASH_SCREEN)
+                .build();
+        view.setNotCopyable();
+        return view;
+    }
+
     private SplashScreenView makeSplashScreenContentView(Context context, StartingWindowInfo info,
             @StartingWindowType int suggestType, Consumer<Runnable> uiThreadInitConsumer) {
         updateDensity();
@@ -263,7 +428,8 @@
         final int themeBGColor = legacyDrawable != null
                 ? getBGColorFromCache(ai, () -> estimateWindowBGColor(legacyDrawable))
                 : getBGColorFromCache(ai, () -> peekWindowBGColor(context, mTmpAttrs));
-        return new StartingWindowViewBuilder(context, ai)
+
+        return new SplashViewBuilder(context, ai)
                 .setWindowBGColor(themeBGColor)
                 .overlayDrawable(legacyDrawable)
                 .chooseStyle(suggestType)
@@ -322,6 +488,14 @@
         private Drawable mSplashScreenIcon = null;
         private Drawable mBrandingImage = null;
         private int mIconBgColor = Color.TRANSPARENT;
+
+        void reset() {
+            mWindowBgResId = 0;
+            mWindowBgColor = Color.TRANSPARENT;
+            mSplashScreenIcon = null;
+            mBrandingImage = null;
+            mIconBgColor = Color.TRANSPARENT;
+        }
     }
 
     /**
@@ -351,7 +525,7 @@
         return appReadyDuration;
     }
 
-    private class StartingWindowViewBuilder {
+    private class SplashViewBuilder {
         private final Context mContext;
         private final ActivityInfo mActivityInfo;
 
@@ -364,27 +538,28 @@
         /** @see #setAllowHandleSolidColor(boolean) **/
         private boolean mAllowHandleSolidColor;
 
-        StartingWindowViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) {
+        SplashViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) {
             mContext = context;
             mActivityInfo = aInfo;
         }
 
-        StartingWindowViewBuilder setWindowBGColor(@ColorInt int background) {
+        SplashViewBuilder setWindowBGColor(@ColorInt int background) {
             mThemeColor = background;
             return this;
         }
 
-        StartingWindowViewBuilder overlayDrawable(Drawable overlay) {
+        SplashViewBuilder overlayDrawable(Drawable overlay) {
             mOverlayDrawable = overlay;
             return this;
         }
 
-        StartingWindowViewBuilder chooseStyle(int suggestType) {
+        SplashViewBuilder chooseStyle(int suggestType) {
             mSuggestType = suggestType;
             return this;
         }
 
-        StartingWindowViewBuilder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) {
+        // Set up the UI thread for the View.
+        SplashViewBuilder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) {
             mUiThreadInitTask = uiThreadInitTask;
             return this;
         }
@@ -395,7 +570,7 @@
          * android.window.SplashScreen.OnExitAnimationListener#onSplashScreenExit(SplashScreenView)}
          * callback, effectively copying the {@link SplashScreenView} into the client process.
          */
-        StartingWindowViewBuilder setAllowHandleSolidColor(boolean allowHandleSolidColor) {
+        SplashViewBuilder setAllowHandleSolidColor(boolean allowHandleSolidColor) {
             mAllowHandleSolidColor = allowHandleSolidColor;
             return this;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index 7f6bfd2..e419462 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -62,7 +62,7 @@
      */
     static Drawable[] makeIconDrawable(@ColorInt int backgroundColor, @ColorInt int themeColor,
             @NonNull Drawable foregroundDrawable, int srcIconSize, int iconSize,
-            boolean loadInDetail, Handler splashscreenWorkerHandler) {
+            boolean loadInDetail, Handler preDrawHandler) {
         Drawable foreground;
         Drawable background = null;
         boolean drawBackground =
@@ -74,13 +74,13 @@
             // If the icon is Adaptive, we already use the icon background.
             drawBackground = false;
             foreground = new ImmobileIconDrawable(foregroundDrawable,
-                    srcIconSize, iconSize, loadInDetail, splashscreenWorkerHandler);
+                    srcIconSize, iconSize, loadInDetail, preDrawHandler);
         } else {
             // Adaptive icon don't handle transparency so we draw the background of the adaptive
             // icon with the same color as the window background color instead of using two layers
             foreground = new ImmobileIconDrawable(
                     new AdaptiveForegroundDrawable(foregroundDrawable),
-                    srcIconSize, iconSize, loadInDetail, splashscreenWorkerHandler);
+                    srcIconSize, iconSize, loadInDetail, preDrawHandler);
         }
 
         if (drawBackground) {
@@ -91,9 +91,9 @@
     }
 
     static Drawable[] makeLegacyIconDrawable(@NonNull Drawable iconDrawable, int srcIconSize,
-            int iconSize, boolean loadInDetail, Handler splashscreenWorkerHandler) {
+            int iconSize, boolean loadInDetail, Handler preDrawHandler) {
         return new Drawable[]{new ImmobileIconDrawable(iconDrawable, srcIconSize, iconSize,
-                loadInDetail, splashscreenWorkerHandler)};
+                loadInDetail, preDrawHandler)};
     }
 
     /**
@@ -107,14 +107,14 @@
         private Bitmap mIconBitmap;
 
         ImmobileIconDrawable(Drawable drawable, int srcIconSize, int iconSize, boolean loadInDetail,
-                Handler splashscreenWorkerHandler) {
+                Handler preDrawHandler) {
             // This icon has lower density, don't scale it.
             if (loadInDetail) {
-                splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, iconSize));
+                preDrawHandler.post(() -> preDrawIcon(drawable, iconSize));
             } else {
                 final float scale = (float) iconSize / srcIconSize;
                 mMatrix.setScale(scale, scale);
-                splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, srcIconSize));
+                preDrawHandler.post(() -> preDrawIcon(drawable, srcIconSize));
             }
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index ff6f2b0..ae3f8e9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.startingsurface;
 
-import static android.content.Context.CONTEXT_RESTRICTED;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Choreographer.CALLBACK_INSETS_ANIMATION;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -32,8 +31,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.PixelFormat;
@@ -198,118 +195,21 @@
         if (activityInfo == null || activityInfo.packageName == null) {
             return;
         }
-
-        final int displayId = taskInfo.displayId;
-        final int taskId = taskInfo.taskId;
-
         // replace with the default theme if the application didn't set
         final int theme = getSplashScreenTheme(windowInfo.splashScreenThemeResId, activityInfo);
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
-                "addSplashScreen for package: %s with theme: %s for task: %d, suggestType: %d",
-                activityInfo.packageName, Integer.toHexString(theme), taskId, suggestType);
-        final Display display = getDisplay(displayId);
-        if (display == null) {
-            // Can't show splash screen on requested display, so skip showing at all.
-            return;
-        }
-        Context context = displayId == DEFAULT_DISPLAY
-                ? mContext : mContext.createDisplayContext(display);
+        final Context context = SplashscreenContentDrawer.createContext(mContext, windowInfo, theme,
+                suggestType, mDisplayManager);
         if (context == null) {
             return;
         }
-        if (theme != context.getThemeResId()) {
-            try {
-                context = context.createPackageContextAsUser(activityInfo.packageName,
-                        CONTEXT_RESTRICTED, UserHandle.of(taskInfo.userId));
-                context.setTheme(theme);
-            } catch (PackageManager.NameNotFoundException e) {
-                Slog.w(TAG, "Failed creating package context with package name "
-                        + activityInfo.packageName + " for user " + taskInfo.userId, e);
-                return;
-            }
-        }
+        final WindowManager.LayoutParams params = SplashscreenContentDrawer.createLayoutParameters(
+                context, windowInfo, suggestType, activityInfo.packageName,
+                suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
+                        ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT, appToken);
 
-        final Configuration taskConfig = taskInfo.getConfiguration();
-        if (taskConfig.diffPublicOnly(context.getResources().getConfiguration()) != 0) {
-            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
-                    "addSplashScreen: creating context based on task Configuration %s",
-                    taskConfig);
-            final Context overrideContext = context.createConfigurationContext(taskConfig);
-            overrideContext.setTheme(theme);
-            final TypedArray typedArray = overrideContext.obtainStyledAttributes(
-                    com.android.internal.R.styleable.Window);
-            final int resId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0);
-            try {
-                if (resId != 0 && overrideContext.getDrawable(resId) != null) {
-                    // We want to use the windowBackground for the override context if it is
-                    // available, otherwise we use the default one to make sure a themed starting
-                    // window is displayed for the app.
-                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
-                            "addSplashScreen: apply overrideConfig %s",
-                            taskConfig);
-                    context = overrideContext;
-                }
-            } catch (Resources.NotFoundException e) {
-                Slog.w(TAG, "failed creating starting window for overrideConfig at taskId: "
-                        + taskId, e);
-                return;
-            }
-            typedArray.recycle();
-        }
-
-        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
-                WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
-        params.setFitInsetsSides(0);
-        params.setFitInsetsTypes(0);
-        params.format = suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
-                ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT;
-        int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
-                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-        final TypedArray a = context.obtainStyledAttributes(R.styleable.Window);
-        if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
-            windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-        }
-        if (suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
-            if (a.getBoolean(R.styleable.Window_windowDrawsSystemBarBackgrounds, false)) {
-                windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-            }
-        } else {
-            windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        }
-        params.layoutInDisplayCutoutMode = a.getInt(
-                R.styleable.Window_windowLayoutInDisplayCutoutMode,
-                params.layoutInDisplayCutoutMode);
-        params.windowAnimations = a.getResourceId(R.styleable.Window_windowAnimationStyle, 0);
-        a.recycle();
-
-        // Assumes it's safe to show starting windows of launched apps while
-        // the keyguard is being hidden. This is okay because starting windows never show
-        // secret information.
-        // TODO(b/113840485): Occluded may not only happen on default display
-        if (displayId == DEFAULT_DISPLAY && windowInfo.isKeyguardOccluded) {
-            windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
-        }
-
-        // Force the window flags: this is a fake window, so it is not really
-        // touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM
-        // flag because we do know that the next window will take input
-        // focus, so we want to get the IME window up on top of us right away.
-        // Touches will only pass through to the host activity window and will be blocked from
-        // passing to any other windows.
-        windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        params.flags = windowFlags;
-        params.token = appToken;
-        params.packageName = activityInfo.packageName;
-        params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
-
-        if (!context.getResources().getCompatibilityInfo().supportsScreen()) {
-            params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-        }
-
-        params.setTitle("Splash Screen " + activityInfo.packageName);
+        final int displayId = taskInfo.displayId;
+        final int taskId = taskInfo.taskId;
+        final Display display = getDisplay(displayId);
 
         // TODO(b/173975965) tracking performance
         // Prepare the splash screen content view on splash screen worker thread in parallel, so the
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 3929e83..9d6711f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -18,50 +18,16 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.graphics.Color.WHITE;
-import static android.graphics.Color.alpha;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
-import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
-import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
-import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 
-import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
-import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
-import static com.android.internal.policy.DecorView.getNavigationBarRect;
-
 import android.annotation.BinderThread;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManager.TaskDescription;
-import android.app.ActivityThread;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.GraphicBuffer;
-import android.graphics.Matrix;
 import android.graphics.Paint;
-import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.RectF;
-import android.hardware.HardwareBuffer;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -73,20 +39,14 @@
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.SurfaceControl;
-import android.view.SurfaceSession;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.window.ClientWindowFrames;
+import android.window.SnapshotDrawerUtils;
 import android.window.StartingWindowInfo;
 import android.window.TaskSnapshot;
 
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.DecorView;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.view.BaseIWindow;
 import com.android.wm.shell.common.ShellExecutor;
@@ -100,27 +60,8 @@
  * @hide
  */
 public class TaskSnapshotWindow {
-    /**
-     * When creating the starting window, we use the exact same layout flags such that we end up
-     * with a window with the exact same dimensions etc. However, these flags are not used in layout
-     * and might cause other side effects so we exclude them.
-     */
-    static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
-            | FLAG_NOT_TOUCHABLE
-            | FLAG_NOT_TOUCH_MODAL
-            | FLAG_ALT_FOCUSABLE_IM
-            | FLAG_NOT_FOCUSABLE
-            | FLAG_HARDWARE_ACCELERATED
-            | FLAG_IGNORE_CHEEK_PRESSES
-            | FLAG_LOCAL_FOCUS_MODE
-            | FLAG_SLIPPERY
-            | FLAG_WATCH_OUTSIDE_TOUCH
-            | FLAG_SPLIT_TOUCH
-            | FLAG_SCALED
-            | FLAG_SECURE;
-
     private static final String TAG = StartingWindowController.TAG;
-    private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
+    private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=";
 
     private static final long DELAY_REMOVAL_TIME_GENERAL = 100;
     /**
@@ -133,25 +74,12 @@
     private final Window mWindow;
     private final Runnable mClearWindowHandler;
     private final ShellExecutor mSplashScreenExecutor;
-    private final SurfaceControl mSurfaceControl;
     private final IWindowSession mSession;
-    private final Rect mTaskBounds;
-    private final Rect mFrame = new Rect();
-    private final Rect mSystemBarInsets = new Rect();
-    private TaskSnapshot mSnapshot;
-    private final RectF mTmpSnapshotSize = new RectF();
-    private final RectF mTmpDstFrame = new RectF();
-    private final CharSequence mTitle;
     private boolean mHasDrawn;
-    private boolean mSizeMismatch;
     private final Paint mBackgroundPaint = new Paint();
     private final int mActivityType;
-    private final int mStatusBarColor;
-    private final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
     private final int mOrientationOnCreation;
-    private final SurfaceControl.Transaction mTransaction;
-    private final Matrix mSnapshotMatrix = new Matrix();
-    private final float[] mTmpFloat9 = new float[9];
+
     private final Runnable mScheduledRunnable = this::removeImmediately;
     private final boolean mHasImeSurface;
 
@@ -163,42 +91,15 @@
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
                 "create taskSnapshot surface for task: %d", taskId);
 
-        final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams;
-        final WindowManager.LayoutParams mainWindowParams = info.mainWindowLayoutParams;
         final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState;
-        if (attrs == null || mainWindowParams == null || topWindowInsetsState == null) {
-            Slog.w(TAG, "unable to create taskSnapshot surface for task: " + taskId);
+
+        final WindowManager.LayoutParams layoutParams = SnapshotDrawerUtils.createLayoutParameters(
+                info, TITLE_FORMAT + taskId, TYPE_APPLICATION_STARTING,
+                snapshot.getHardwareBuffer().getFormat(), appToken);
+        if (layoutParams == null) {
+            Slog.e(TAG, "TaskSnapshotWindow no layoutParams");
             return null;
         }
-        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
-
-        final int appearance = attrs.insetsFlags.appearance;
-        final int windowFlags = attrs.flags;
-        final int windowPrivateFlags = attrs.privateFlags;
-
-        layoutParams.packageName = mainWindowParams.packageName;
-        layoutParams.windowAnimations = mainWindowParams.windowAnimations;
-        layoutParams.dimAmount = mainWindowParams.dimAmount;
-        layoutParams.type = TYPE_APPLICATION_STARTING;
-        layoutParams.format = snapshot.getHardwareBuffer().getFormat();
-        layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
-                | FLAG_NOT_FOCUSABLE
-                | FLAG_NOT_TOUCHABLE;
-        // Setting as trusted overlay to let touches pass through. This is safe because this
-        // window is controlled by the system.
-        layoutParams.privateFlags = (windowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS)
-                | PRIVATE_FLAG_TRUSTED_OVERLAY | PRIVATE_FLAG_USE_BLAST;
-        layoutParams.token = appToken;
-        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
-        layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
-        layoutParams.insetsFlags.appearance = appearance;
-        layoutParams.insetsFlags.behavior = attrs.insetsFlags.behavior;
-        layoutParams.layoutInDisplayCutoutMode = attrs.layoutInDisplayCutoutMode;
-        layoutParams.setFitInsetsTypes(attrs.getFitInsetsTypes());
-        layoutParams.setFitInsetsSides(attrs.getFitInsetsSides());
-        layoutParams.setFitInsetsIgnoringVisibility(attrs.isFitInsetsIgnoringVisibility());
-
-        layoutParams.setTitle(String.format(TITLE_FORMAT, taskId));
 
         final Point taskSize = snapshot.getTaskSize();
         final Rect taskBounds = new Rect(0, 0, taskSize.x, taskSize.y);
@@ -222,9 +123,8 @@
         }
 
         final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow(
-                surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
-                windowFlags, windowPrivateFlags, taskBounds, orientation, activityType,
-                info.requestedVisibleTypes, clearWindowHandler, splashScreenExecutor);
+                snapshot, taskDescription, orientation, activityType,
+                clearWindowHandler, splashScreenExecutor);
         final Window window = snapshotSurface.mWindow;
 
         final InsetsState tmpInsetsState = new InsetsState();
@@ -255,33 +155,25 @@
             snapshotSurface.clearWindowSynced();
         }
 
-        final Rect systemBarInsets = getSystemBarInsets(tmpFrames.frame, topWindowInsetsState);
-        snapshotSurface.setFrames(tmpFrames.frame, systemBarInsets);
-        snapshotSurface.drawSnapshot();
+        SnapshotDrawerUtils.drawSnapshotOnSurface(info, layoutParams, surfaceControl, snapshot,
+                taskBounds, tmpFrames.frame, topWindowInsetsState, true /* releaseAfterDraw */);
+        snapshotSurface.mHasDrawn = true;
+        snapshotSurface.reportDrawn();
+
         return snapshotSurface;
     }
 
-    public TaskSnapshotWindow(SurfaceControl surfaceControl,
-            TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
-            int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
-            int currentOrientation, int activityType, @InsetsType int requestedVisibleTypes,
-            Runnable clearWindowHandler, ShellExecutor splashScreenExecutor) {
+    public TaskSnapshotWindow(TaskSnapshot snapshot, TaskDescription taskDescription,
+            int currentOrientation, int activityType, Runnable clearWindowHandler,
+            ShellExecutor splashScreenExecutor) {
         mSplashScreenExecutor = splashScreenExecutor;
         mSession = WindowManagerGlobal.getWindowSession();
         mWindow = new Window();
         mWindow.setSession(mSession);
-        mSurfaceControl = surfaceControl;
-        mSnapshot = snapshot;
-        mTitle = title;
         int backgroundColor = taskDescription.getBackgroundColor();
         mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
-        mTaskBounds = taskBounds;
-        mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
-                windowPrivateFlags, appearance, taskDescription, 1f, requestedVisibleTypes);
-        mStatusBarColor = taskDescription.getStatusBarColor();
         mOrientationOnCreation = currentOrientation;
         mActivityType = activityType;
-        mTransaction = new SurfaceControl.Transaction();
         mClearWindowHandler = clearWindowHandler;
         mHasImeSurface = snapshot.hasImeSurface();
     }
@@ -294,23 +186,6 @@
 	return mHasImeSurface;
     }
 
-    /**
-     * Ask system bar background painter to draw status bar background.
-     * @hide
-     */
-    public void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame) {
-        mSystemBarBackgroundPainter.drawStatusBarBackground(c, alreadyDrawnFrame,
-                mSystemBarBackgroundPainter.getStatusBarColorViewHeight());
-    }
-
-    /**
-     * Ask system bar background painter to draw navigation bar background.
-     * @hide
-     */
-    public void drawNavigationBarBackground(Canvas c) {
-        mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
-    }
-
     void scheduleRemove(boolean deferRemoveForIme) {
         // Show the latest content as soon as possible for unlocking to home.
         if (mActivityType == ACTIVITY_TYPE_HOME) {
@@ -338,178 +213,6 @@
     }
 
     /**
-     * Set frame size.
-     * @hide
-     */
-    public void setFrames(Rect frame, Rect systemBarInsets) {
-        mFrame.set(frame);
-        mSystemBarInsets.set(systemBarInsets);
-        final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
-        mSizeMismatch = (mFrame.width() != snapshot.getWidth()
-                || mFrame.height() != snapshot.getHeight());
-        mSystemBarBackgroundPainter.setInsets(systemBarInsets);
-    }
-
-    static Rect getSystemBarInsets(Rect frame, InsetsState state) {
-        return state.calculateInsets(frame, WindowInsets.Type.systemBars(),
-                false /* ignoreVisibility */).toRect();
-    }
-
-    private void drawSnapshot() {
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
-                "Drawing snapshot surface sizeMismatch=%b", mSizeMismatch);
-        if (mSizeMismatch) {
-            // The dimensions of the buffer and the window don't match, so attaching the buffer
-            // will fail. Better create a child window with the exact dimensions and fill the parent
-            // window with the background color!
-            drawSizeMismatchSnapshot();
-        } else {
-            drawSizeMatchSnapshot();
-        }
-        mHasDrawn = true;
-        reportDrawn();
-
-        // In case window manager leaks us, make sure we don't retain the snapshot.
-        if (mSnapshot.getHardwareBuffer() != null) {
-            mSnapshot.getHardwareBuffer().close();
-        }
-        mSnapshot = null;
-        mSurfaceControl.release();
-    }
-
-    private void drawSizeMatchSnapshot() {
-        mTransaction.setBuffer(mSurfaceControl, mSnapshot.getHardwareBuffer())
-                .setColorSpace(mSurfaceControl, mSnapshot.getColorSpace())
-                .apply();
-    }
-
-    private void drawSizeMismatchSnapshot() {
-        final HardwareBuffer buffer = mSnapshot.getHardwareBuffer();
-        final SurfaceSession session = new SurfaceSession();
-
-        // We consider nearly matched dimensions as there can be rounding errors and the user won't
-        // notice very minute differences from scaling one dimension more than the other
-        final boolean aspectRatioMismatch = Math.abs(
-                ((float) buffer.getWidth() / buffer.getHeight())
-                - ((float) mFrame.width() / mFrame.height())) > 0.01f;
-
-        // Keep a reference to it such that it doesn't get destroyed when finalized.
-        SurfaceControl childSurfaceControl = new SurfaceControl.Builder(session)
-                .setName(mTitle + " - task-snapshot-surface")
-                .setBLASTLayer()
-                .setFormat(buffer.getFormat())
-                .setParent(mSurfaceControl)
-                .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot")
-                .build();
-
-        final Rect frame;
-        // We can just show the surface here as it will still be hidden as the parent is
-        // still hidden.
-        mTransaction.show(childSurfaceControl);
-        if (aspectRatioMismatch) {
-            // Clip off ugly navigation bar.
-            final Rect crop = calculateSnapshotCrop();
-            frame = calculateSnapshotFrame(crop);
-            mTransaction.setWindowCrop(childSurfaceControl, crop);
-            mTransaction.setPosition(childSurfaceControl, frame.left, frame.top);
-            mTmpSnapshotSize.set(crop);
-            mTmpDstFrame.set(frame);
-        } else {
-            frame = null;
-            mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
-            mTmpDstFrame.set(mFrame);
-            mTmpDstFrame.offsetTo(0, 0);
-        }
-
-        // Scale the mismatch dimensions to fill the task bounds
-        mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL);
-        mTransaction.setMatrix(childSurfaceControl, mSnapshotMatrix, mTmpFloat9);
-        mTransaction.setColorSpace(childSurfaceControl, mSnapshot.getColorSpace());
-        mTransaction.setBuffer(childSurfaceControl, mSnapshot.getHardwareBuffer());
-
-        if (aspectRatioMismatch) {
-            GraphicBuffer background = GraphicBuffer.create(mFrame.width(), mFrame.height(),
-                    PixelFormat.RGBA_8888,
-                    GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_HW_COMPOSER
-                            | GraphicBuffer.USAGE_SW_WRITE_RARELY);
-            // TODO: Support this on HardwareBuffer
-            final Canvas c = background.lockCanvas();
-            drawBackgroundAndBars(c, frame);
-            background.unlockCanvasAndPost(c);
-            mTransaction.setBuffer(mSurfaceControl,
-                    HardwareBuffer.createFromGraphicBuffer(background));
-        }
-        mTransaction.apply();
-        childSurfaceControl.release();
-    }
-
-    /**
-     * Calculates the snapshot crop in snapshot coordinate space.
-     *
-     * @return crop rect in snapshot coordinate space.
-     */
-    public Rect calculateSnapshotCrop() {
-        final Rect rect = new Rect();
-        final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
-        rect.set(0, 0, snapshot.getWidth(), snapshot.getHeight());
-        final Rect insets = mSnapshot.getContentInsets();
-
-        final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
-        final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
-
-        // Let's remove all system decorations except the status bar, but only if the task is at the
-        // very top of the screen.
-        final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
-        rect.inset((int) (insets.left * scaleX),
-                isTop ? 0 : (int) (insets.top * scaleY),
-                (int) (insets.right * scaleX),
-                (int) (insets.bottom * scaleY));
-        return rect;
-    }
-
-    /**
-     * Calculates the snapshot frame in window coordinate space from crop.
-     *
-     * @param crop rect that is in snapshot coordinate space.
-     */
-    public Rect calculateSnapshotFrame(Rect crop) {
-        final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
-        final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
-        final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
-
-        // Rescale the frame from snapshot to window coordinate space
-        final Rect frame = new Rect(0, 0,
-                (int) (crop.width() / scaleX + 0.5f),
-                (int) (crop.height() / scaleY + 0.5f)
-        );
-
-        // However, we also need to make space for the navigation bar on the left side.
-        frame.offset(mSystemBarInsets.left, 0);
-        return frame;
-    }
-
-    /**
-     * Draw status bar and navigation bar background.
-     * @hide
-     */
-    public void drawBackgroundAndBars(Canvas c, Rect frame) {
-        final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
-        final boolean fillHorizontally = c.getWidth() > frame.right;
-        final boolean fillVertically = c.getHeight() > frame.bottom;
-        if (fillHorizontally) {
-            c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
-                    c.getWidth(), fillVertically
-                            ? frame.bottom
-                            : c.getHeight(),
-                    mBackgroundPaint);
-        }
-        if (fillVertically) {
-            c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
-        }
-        mSystemBarBackgroundPainter.drawDecors(c, frame);
-    }
-
-    /**
      * Clear window from drawer, must be post on main executor.
      */
     private void clearWindowSynced() {
@@ -557,92 +260,4 @@
             });
         }
     }
-
-    /**
-     * Helper class to draw the background of the system bars in regions the task snapshot isn't
-     * filling the window.
-     */
-    static class SystemBarBackgroundPainter {
-        private final Paint mStatusBarPaint = new Paint();
-        private final Paint mNavigationBarPaint = new Paint();
-        private final int mStatusBarColor;
-        private final int mNavigationBarColor;
-        private final int mWindowFlags;
-        private final int mWindowPrivateFlags;
-        private final float mScale;
-        private final @InsetsType int mRequestedVisibleTypes;
-        private final Rect mSystemBarInsets = new Rect();
-
-        SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int appearance,
-                TaskDescription taskDescription, float scale,
-                @InsetsType int requestedVisibleTypes) {
-            mWindowFlags = windowFlags;
-            mWindowPrivateFlags = windowPrivateFlags;
-            mScale = scale;
-            final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
-            final int semiTransparent = context.getColor(
-                    R.color.system_bar_background_semi_transparent);
-            mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
-                    semiTransparent, taskDescription.getStatusBarColor(), appearance,
-                    APPEARANCE_LIGHT_STATUS_BARS,
-                    taskDescription.getEnsureStatusBarContrastWhenTransparent());
-            mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
-                    FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
-                    taskDescription.getNavigationBarColor(), appearance,
-                    APPEARANCE_LIGHT_NAVIGATION_BARS,
-                    taskDescription.getEnsureNavigationBarContrastWhenTransparent()
-                            && context.getResources().getBoolean(R.bool.config_navBarNeedsScrim));
-            mStatusBarPaint.setColor(mStatusBarColor);
-            mNavigationBarPaint.setColor(mNavigationBarColor);
-            mRequestedVisibleTypes = requestedVisibleTypes;
-        }
-
-        void setInsets(Rect systemBarInsets) {
-            mSystemBarInsets.set(systemBarInsets);
-        }
-
-        int getStatusBarColorViewHeight() {
-            final boolean forceBarBackground =
-                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
-            if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                    mRequestedVisibleTypes, mStatusBarColor, mWindowFlags, forceBarBackground)) {
-                return (int) (mSystemBarInsets.top * mScale);
-            } else {
-                return 0;
-            }
-        }
-
-        private boolean isNavigationBarColorViewVisible() {
-            final boolean forceBarBackground =
-                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
-            return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                    mRequestedVisibleTypes, mNavigationBarColor, mWindowFlags, forceBarBackground);
-        }
-
-        void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
-            drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
-            drawNavigationBarBackground(c);
-        }
-
-        void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
-                int statusBarHeight) {
-            if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
-                    && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
-                final int rightInset = (int) (mSystemBarInsets.right * mScale);
-                final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
-                c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
-            }
-        }
-
-        @VisibleForTesting
-        void drawNavigationBarBackground(Canvas c) {
-            final Rect navigationBarRect = new Rect();
-            getNavigationBarRect(c.getWidth(), c.getHeight(), mSystemBarInsets, navigationBarRect,
-                    mScale);
-            final boolean visible = isNavigationBarColorViewVisible();
-            if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
-                c.drawRect(navigationBarRect, mNavigationBarPaint);
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 60376f4..6f71b72 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -200,7 +200,6 @@
 import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
-import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -4587,55 +4586,6 @@
         return new TouchHandler();
     }
 
-    private final PhoneStatusBarView.TouchEventHandler mStatusBarViewTouchEventHandler =
-            new PhoneStatusBarView.TouchEventHandler() {
-                @Override
-                public void onInterceptTouchEvent(MotionEvent event) {
-                    mCentralSurfaces.onTouchEvent(event);
-                }
-
-                @Override
-                public boolean handleTouchEvent(MotionEvent event) {
-                    mCentralSurfaces.onTouchEvent(event);
-
-                    // TODO(b/202981994): Move the touch debugging in this method to a central
-                    //  location. (Right now, it's split between CentralSurfaces and here.)
-
-                    // If panels aren't enabled, ignore the gesture and don't pass it down to the
-                    // panel view.
-                    if (!mCommandQueue.panelsEnabled()) {
-                        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                            Log.v(
-                                    TAG,
-                                    String.format(
-                                            "onTouchForwardedFromStatusBar: "
-                                                    + "panel disabled, ignoring touch at (%d,%d)",
-                                            (int) event.getX(),
-                                            (int) event.getY()
-                                    )
-                            );
-                        }
-                        return false;
-                    }
-
-                    if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                        // If the view that would receive the touch is disabled, just have status
-                        // bar eat the gesture.
-                        if (!mView.isEnabled()) {
-                            mShadeLog.logMotionEvent(event,
-                                    "onTouchForwardedFromStatusBar: panel view disabled");
-                            return true;
-                        }
-                        if (isFullyCollapsed() && event.getY() < 1f) {
-                            // b/235889526 Eat events on the top edge of the phone when collapsed
-                            mShadeLog.logMotionEvent(event, "top edge touch ignored");
-                            return true;
-                        }
-                    }
-                    return mView.dispatchTouchEvent(event);
-                }
-            };
-
     public NotificationStackScrollLayoutController getNotificationStackScrollLayoutController() {
         return mNotificationStackScrollLayoutController;
     }
@@ -5238,6 +5188,11 @@
     }
 
     /** */
+    public boolean sendTouchEventToView(MotionEvent event) {
+        return mView.dispatchTouchEvent(event);
+    }
+
+    /** */
     public void requestLayoutOnView() {
         mView.requestLayout();
     }
@@ -5247,6 +5202,11 @@
         ViewGroupFadeHelper.reset(mView);
     }
 
+    /** */
+    public boolean isViewEnabled() {
+        return mView.isEnabled();
+    }
+
     private void beginJankMonitoring() {
         if (mInteractionJankMonitor == null) {
             return;
@@ -5796,11 +5756,6 @@
         mCurrentPanelState = state;
     }
 
-    /** Returns the handler that the status bar should forward touches to. */
-    public PhoneStatusBarView.TouchEventHandler getStatusBarTouchEventHandler() {
-        return mStatusBarViewTouchEventHandler;
-    }
-
     @VisibleForTesting
     StatusBarStateController getStatusBarStateController() {
         return mStatusBarStateController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index e068f87..c7c6441 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -28,7 +28,6 @@
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.RemoteAnimationAdapter;
 import android.view.View;
 import android.view.ViewGroup;
@@ -285,7 +284,11 @@
 
     void animateCollapseQuickSettings();
 
-    void onTouchEvent(MotionEvent event);
+    /** */
+    boolean getCommandQueuePanelsEnabled();
+
+    /** */
+    int getStatusBarWindowState();
 
     BiometricUnlockController getBiometricUnlockController();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index d027ed0..b394535 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -93,7 +93,6 @@
 import android.view.IRemoteAnimationRunner;
 import android.view.IWindowManager;
 import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.ThreadedRenderer;
 import android.view.View;
 import android.view.ViewGroup;
@@ -2011,43 +2010,14 @@
         }
     }
 
-    /** Called when a touch event occurred on {@link PhoneStatusBarView}. */
     @Override
-    public void onTouchEvent(MotionEvent event) {
-        // TODO(b/202981994): Move this touch debugging to a central location. (Right now, it's
-        //   split between NotificationPanelViewController and here.)
-        if (DEBUG_GESTURES) {
-            if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
-                EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
-                        event.getActionMasked(), (int) event.getX(), (int) event.getY(),
-                        mDisabled1, mDisabled2);
-            }
+    public boolean getCommandQueuePanelsEnabled() {
+        return mCommandQueue.panelsEnabled();
+    }
 
-        }
-
-        if (SPEW) {
-            Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1="
-                    + mDisabled1 + " mDisabled2=" + mDisabled2);
-        } else if (CHATTY) {
-            if (event.getAction() != MotionEvent.ACTION_MOVE) {
-                Log.d(TAG, String.format(
-                            "panel: %s at (%f, %f) mDisabled1=0x%08x mDisabled2=0x%08x",
-                            MotionEvent.actionToString(event.getAction()),
-                            event.getRawX(), event.getRawY(), mDisabled1, mDisabled2));
-            }
-        }
-
-        if (DEBUG_GESTURES) {
-            mGestureRec.add(event);
-        }
-
-        if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
-            final boolean upOrCancel =
-                    event.getAction() == MotionEvent.ACTION_UP ||
-                    event.getAction() == MotionEvent.ACTION_CANCEL;
-            setInteracting(StatusBarManager.WINDOW_STATUS_BAR,
-                    !upOrCancel || mShadeController.isExpandedVisible());
-        }
+    @Override
+    public int getStatusBarWindowState() {
+        return mStatusBarWindowState;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index a6c2b2c..11bc490 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -15,14 +15,20 @@
  */
 package com.android.systemui.statusbar.phone
 
+import android.app.StatusBarManager.WINDOW_STATE_SHOWING
+import android.app.StatusBarManager.WINDOW_STATUS_BAR
 import android.content.res.Configuration
 import android.graphics.Point
+import android.util.Log
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewTreeObserver
 import com.android.systemui.R
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.shade.ShadeLogger
 import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
+import com.android.systemui.statusbar.phone.PhoneStatusBarView.TouchEventHandler
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.unfold.SysUIUnfoldComponent
 import com.android.systemui.unfold.UNFOLD_STATUS_BAR
@@ -35,14 +41,18 @@
 import javax.inject.Inject
 import javax.inject.Named
 
+private const val TAG = "PhoneStatusBarViewController"
+
 /** Controller for [PhoneStatusBarView].  */
 class PhoneStatusBarViewController private constructor(
     view: PhoneStatusBarView,
     @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?,
+    private val centralSurfaces: CentralSurfaces,
+    private val shadeController: ShadeController,
+    private val shadeLogger: ShadeLogger,
     private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
     private val userChipViewModel: StatusBarUserChipViewModel,
     private val viewUtil: ViewUtil,
-    touchEventHandler: PhoneStatusBarView.TouchEventHandler,
     private val configurationController: ConfigurationController
 ) : ViewController<PhoneStatusBarView>(view) {
 
@@ -90,7 +100,7 @@
     }
 
     init {
-        mView.setTouchEventHandler(touchEventHandler)
+        mView.setTouchEventHandler(PhoneStatusBarViewTouchHandler())
         mView.init(userChipViewModel)
     }
 
@@ -120,6 +130,54 @@
         return viewUtil.touchIsWithinView(mView, x, y)
     }
 
+    /** Called when a touch event occurred on {@link PhoneStatusBarView}. */
+    fun onTouchEvent(event: MotionEvent) {
+        if (centralSurfaces.statusBarWindowState == WINDOW_STATE_SHOWING) {
+            val upOrCancel =
+                    event.action == MotionEvent.ACTION_UP ||
+                    event.action == MotionEvent.ACTION_CANCEL
+            centralSurfaces.setInteracting(WINDOW_STATUS_BAR,
+                    !upOrCancel || shadeController.isExpandedVisible)
+        }
+    }
+
+    inner class PhoneStatusBarViewTouchHandler : TouchEventHandler {
+        override fun onInterceptTouchEvent(event: MotionEvent) {
+            onTouchEvent(event)
+        }
+
+        override fun handleTouchEvent(event: MotionEvent): Boolean {
+            onTouchEvent(event)
+
+            // If panels aren't enabled, ignore the gesture and don't pass it down to the
+            // panel view.
+            if (!centralSurfaces.commandQueuePanelsEnabled) {
+                if (event.action == MotionEvent.ACTION_DOWN) {
+                    Log.v(TAG, String.format("onTouchForwardedFromStatusBar: panel disabled, " +
+                            "ignoring touch at (${event.x.toInt()},${event.y.toInt()})"))
+                }
+                return false
+            }
+
+            if (event.action == MotionEvent.ACTION_DOWN) {
+                // If the view that would receive the touch is disabled, just have status
+                // bar eat the gesture.
+                if (!centralSurfaces.notificationPanelViewController.isViewEnabled) {
+                    shadeLogger.logMotionEvent(event,
+                            "onTouchForwardedFromStatusBar: panel view disabled")
+                    return true
+                }
+                if (centralSurfaces.notificationPanelViewController.isFullyCollapsed &&
+                        event.y < 1f) {
+                    // b/235889526 Eat events on the top edge of the phone when collapsed
+                    shadeLogger.logMotionEvent(event, "top edge touch ignored")
+                    return true
+                }
+            }
+            return centralSurfaces.notificationPanelViewController.sendTouchEventToView(event)
+        }
+    }
+
     class StatusBarViewsCenterProvider : UnfoldMoveFromCenterAnimator.ViewCenterProvider {
         override fun getViewCenter(view: View, outPoint: Point) =
             when (view.id) {
@@ -157,20 +215,24 @@
         @Named(UNFOLD_STATUS_BAR)
         private val progressProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
         private val userChipViewModel: StatusBarUserChipViewModel,
+        private val centralSurfaces: CentralSurfaces,
+        private val shadeController: ShadeController,
+        private val shadeLogger: ShadeLogger,
         private val viewUtil: ViewUtil,
         private val configurationController: ConfigurationController,
     ) {
         fun create(
-            view: PhoneStatusBarView,
-            touchEventHandler: PhoneStatusBarView.TouchEventHandler
+            view: PhoneStatusBarView
         ) =
             PhoneStatusBarViewController(
                 view,
                 progressProvider.getOrNull(),
+                centralSurfaces,
+                shadeController,
+                shadeLogger,
                 unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController(),
                 userChipViewModel,
                 viewUtil,
-                touchEventHandler,
                 configurationController
             )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
index efec270..730ecde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
@@ -21,7 +21,6 @@
 import com.android.systemui.R;
 import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
@@ -127,11 +126,9 @@
     @StatusBarFragmentScope
     static PhoneStatusBarViewController providePhoneStatusBarViewController(
             PhoneStatusBarViewController.Factory phoneStatusBarViewControllerFactory,
-            @RootView PhoneStatusBarView phoneStatusBarView,
-            NotificationPanelViewController notificationPanelViewController) {
+            @RootView PhoneStatusBarView phoneStatusBarView) {
         return phoneStatusBarViewControllerFactory.create(
-                phoneStatusBarView,
-                notificationPanelViewController.getStatusBarTouchEventHandler());
+                phoneStatusBarView);
     }
 
     /** */
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index b6f74f0..17ba30a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -802,66 +802,6 @@
     }
 
     @Test
-    public void handleTouchEventFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() {
-        when(mCommandQueue.panelsEnabled()).thenReturn(false);
-
-        boolean returnVal = mNotificationPanelViewController
-                .getStatusBarTouchEventHandler()
-                .handleTouchEvent(
-                        MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
-
-        assertThat(returnVal).isFalse();
-        verify(mView, never()).dispatchTouchEvent(any());
-    }
-
-    @Test
-    public void handleTouchEventFromStatusBar_viewNotEnabled_returnsTrueAndNoViewEvent() {
-        when(mCommandQueue.panelsEnabled()).thenReturn(true);
-        when(mView.isEnabled()).thenReturn(false);
-
-        boolean returnVal = mNotificationPanelViewController
-                .getStatusBarTouchEventHandler()
-                .handleTouchEvent(
-                        MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
-
-        assertThat(returnVal).isTrue();
-        verify(mView, never()).dispatchTouchEvent(any());
-    }
-
-    @Test
-    public void handleTouchEventFromStatusBar_viewNotEnabledButIsMoveEvent_viewReceivesEvent() {
-        when(mCommandQueue.panelsEnabled()).thenReturn(true);
-        when(mView.isEnabled()).thenReturn(false);
-        MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0);
-
-        mNotificationPanelViewController.getStatusBarTouchEventHandler().handleTouchEvent(event);
-
-        verify(mView).dispatchTouchEvent(event);
-    }
-
-    @Test
-    public void handleTouchEventFromStatusBar_panelAndViewEnabled_viewReceivesEvent() {
-        when(mCommandQueue.panelsEnabled()).thenReturn(true);
-        when(mView.isEnabled()).thenReturn(true);
-        MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 2f, 0);
-
-        mNotificationPanelViewController.getStatusBarTouchEventHandler().handleTouchEvent(event);
-
-        verify(mView).dispatchTouchEvent(event);
-    }
-
-    @Test
-    public void handleTouchEventFromStatusBar_topEdgeTouch_viewNeverReceivesEvent() {
-        when(mCommandQueue.panelsEnabled()).thenReturn(true);
-        when(mView.isEnabled()).thenReturn(true);
-        MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0);
-
-        mNotificationPanelViewController.getStatusBarTouchEventHandler().handleTouchEvent(event);
-
-        verify(mView, never()).dispatchTouchEvent(event);
-    }
-
-    @Test
     public void testA11y_initializeNode() {
         AccessibilityNodeInfo nodeInfo = new AccessibilityNodeInfo();
         mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(mView, nodeInfo);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index e2843a1..14d239a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -27,6 +27,8 @@
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.shade.ShadeControllerImpl
+import com.android.systemui.shade.ShadeLogger
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.unfold.SysUIUnfoldComponent
 import com.android.systemui.unfold.config.UnfoldTransitionConfig
@@ -41,6 +43,7 @@
 import org.mockito.Mock
 import org.mockito.Mockito.`when`
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
 import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
@@ -49,8 +52,6 @@
 @SmallTest
 class PhoneStatusBarViewControllerTest : SysuiTestCase() {
 
-    private val touchEventHandler = TestTouchEventHandler()
-
     @Mock
     private lateinit var notificationPanelViewController: NotificationPanelViewController
     @Mock
@@ -66,6 +67,12 @@
     @Mock
     private lateinit var userChipViewModel: StatusBarUserChipViewModel
     @Mock
+    private lateinit var centralSurfacesImpl: CentralSurfacesImpl
+    @Mock
+    private lateinit var shadeControllerImpl: ShadeControllerImpl
+    @Mock
+    private lateinit var shadeLogger: ShadeLogger
+    @Mock
     private lateinit var viewUtil: ViewUtil
 
     private lateinit var view: PhoneStatusBarView
@@ -88,18 +95,6 @@
     }
 
     @Test
-    fun constructor_setsTouchHandlerOnView() {
-        val interceptEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 10f, 10f, 0)
-        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
-
-        view.onInterceptTouchEvent(interceptEvent)
-        view.onTouchEvent(event)
-
-        assertThat(touchEventHandler.lastInterceptEvent).isEqualTo(interceptEvent)
-        assertThat(touchEventHandler.lastEvent).isEqualTo(event)
-    }
-
-    @Test
     fun onViewAttachedAndDrawn_moveFromCenterAnimationEnabled_moveFromCenterAnimationInitialized() {
         val view = createViewMock()
         val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java)
@@ -115,6 +110,66 @@
         verify(moveFromCenterAnimation).onViewsReady(any())
     }
 
+    @Test
+    fun handleTouchEventFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() {
+        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(false)
+        val returnVal = view.onTouchEvent(
+                        MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+        assertThat(returnVal).isFalse()
+        verify(notificationPanelViewController, never()).sendTouchEventToView(any())
+    }
+
+    @Test
+    fun handleTouchEventFromStatusBar_viewNotEnabled_returnsTrueAndNoViewEvent() {
+        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
+        `when`(centralSurfacesImpl.notificationPanelViewController)
+                .thenReturn(notificationPanelViewController)
+        `when`(notificationPanelViewController.isViewEnabled).thenReturn(false)
+        val returnVal = view.onTouchEvent(
+                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+        assertThat(returnVal).isTrue()
+        verify(notificationPanelViewController, never()).sendTouchEventToView(any())
+    }
+
+    @Test
+    fun handleTouchEventFromStatusBar_viewNotEnabledButIsMoveEvent_viewReceivesEvent() {
+        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
+        `when`(centralSurfacesImpl.notificationPanelViewController)
+                .thenReturn(notificationPanelViewController)
+        `when`(notificationPanelViewController.isViewEnabled).thenReturn(false)
+        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
+
+        view.onTouchEvent(event)
+
+        verify(notificationPanelViewController).sendTouchEventToView(event)
+    }
+
+    @Test
+    fun handleTouchEventFromStatusBar_panelAndViewEnabled_viewReceivesEvent() {
+        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
+        `when`(centralSurfacesImpl.notificationPanelViewController)
+                .thenReturn(notificationPanelViewController)
+        `when`(notificationPanelViewController.isViewEnabled).thenReturn(true)
+        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 2f, 0)
+
+        view.onTouchEvent(event)
+
+        verify(notificationPanelViewController).sendTouchEventToView(event)
+    }
+
+    @Test
+    fun handleTouchEventFromStatusBar_topEdgeTouch_viewNeverReceivesEvent() {
+        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
+        `when`(centralSurfacesImpl.notificationPanelViewController)
+                .thenReturn(notificationPanelViewController)
+        `when`(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+
+        view.onTouchEvent(event)
+
+        verify(notificationPanelViewController, never()).sendTouchEventToView(any())
+    }
+
     private fun createViewMock(): PhoneStatusBarView {
         val view = spy(view)
         val viewTreeObserver = mock(ViewTreeObserver::class.java)
@@ -128,9 +183,12 @@
             Optional.of(sysuiUnfoldComponent),
             Optional.of(progressProvider),
             userChipViewModel,
+            centralSurfacesImpl,
+            shadeControllerImpl,
+            shadeLogger,
             viewUtil,
             configurationController
-        ).create(view, touchEventHandler).also {
+        ).create(view).also {
             it.init()
         }
     }
@@ -140,17 +198,4 @@
         override var isHingeAngleEnabled: Boolean = false
         override val halfFoldedTimeoutMillis: Int = 0
     }
-
-    private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
-        var lastEvent: MotionEvent? = null
-        var lastInterceptEvent: MotionEvent? = null
-
-        override fun onInterceptTouchEvent(event: MotionEvent?) {
-            lastInterceptEvent = event
-        }
-        override fun handleTouchEvent(event: MotionEvent?): Boolean {
-            lastEvent = event
-            return false
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 29c98b9..c1b9e662 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -16,29 +16,14 @@
 
 package com.android.server.wm;
 
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-
-import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
-import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
-import static com.android.internal.policy.DecorView.getNavigationBarRect;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityThread;
-import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.RecordingCanvas;
@@ -59,12 +44,11 @@
 import android.view.WindowInsetsController.Appearance;
 import android.view.WindowManager.LayoutParams;
 import android.window.ScreenCapture;
+import android.window.SnapshotDrawerUtils;
 import android.window.TaskSnapshot;
 
-import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
-import com.android.internal.policy.DecorView;
 import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
 import com.android.server.wm.utils.InsetUtils;
 
@@ -585,7 +569,8 @@
         final Rect taskBounds = task.getBounds();
         final InsetsState insetsState = mainWindow.getInsetsStateWithVisibilityOverride();
         final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrame(), insetsState);
-        final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
+        final SnapshotDrawerUtils.SystemBarBackgroundPainter decorPainter =
+                new SnapshotDrawerUtils.SystemBarBackgroundPainter(attrs.flags,
                 attrs.privateFlags, attrs.insetsFlags.appearance, task.getTaskDescription(),
                 mHighResTaskSnapshotScale, mainWindow.getRequestedVisibleTypes());
         final int taskWidth = taskBounds.width();
@@ -599,7 +584,7 @@
         final RecordingCanvas c = node.start(width, height);
         c.drawColor(color);
         decorPainter.setInsets(systemBarInsets);
-        decorPainter.drawDecors(c /* statusBarExcludeFrame */);
+        decorPainter.drawDecors(c /* statusBarExcludeFrame */, null /* alreadyDrawnFrame */);
         node.end(c);
         final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height);
         if (hwBitmap == null) {
@@ -736,92 +721,4 @@
         pw.println(prefix + "mTaskSnapshotEnabled=" + mTaskSnapshotEnabled);
         mCache.dump(pw, prefix);
     }
-
-    /**
-     * Helper class to draw the background of the system bars in regions the task snapshot isn't
-     * filling the window.
-     */
-    static class SystemBarBackgroundPainter {
-
-        private final Paint mStatusBarPaint = new Paint();
-        private final Paint mNavigationBarPaint = new Paint();
-        private final int mStatusBarColor;
-        private final int mNavigationBarColor;
-        private final int mWindowFlags;
-        private final int mWindowPrivateFlags;
-        private final float mScale;
-        private final @Type.InsetsType int mRequestedVisibleTypes;
-        private final Rect mSystemBarInsets = new Rect();
-
-        SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int appearance,
-                ActivityManager.TaskDescription taskDescription, float scale,
-                @Type.InsetsType int requestedVisibleTypes) {
-            mWindowFlags = windowFlags;
-            mWindowPrivateFlags = windowPrivateFlags;
-            mScale = scale;
-            final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
-            final int semiTransparent = context.getColor(
-                    R.color.system_bar_background_semi_transparent);
-            mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
-                    semiTransparent, taskDescription.getStatusBarColor(), appearance,
-                    APPEARANCE_LIGHT_STATUS_BARS,
-                    taskDescription.getEnsureStatusBarContrastWhenTransparent());
-            mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
-                    FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
-                    taskDescription.getNavigationBarColor(), appearance,
-                    APPEARANCE_LIGHT_NAVIGATION_BARS,
-                    taskDescription.getEnsureNavigationBarContrastWhenTransparent()
-                            && context.getResources().getBoolean(R.bool.config_navBarNeedsScrim));
-            mStatusBarPaint.setColor(mStatusBarColor);
-            mNavigationBarPaint.setColor(mNavigationBarColor);
-            mRequestedVisibleTypes = requestedVisibleTypes;
-        }
-
-        void setInsets(Rect systemBarInsets) {
-            mSystemBarInsets.set(systemBarInsets);
-        }
-
-        int getStatusBarColorViewHeight() {
-            final boolean forceBarBackground =
-                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
-            if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                    mRequestedVisibleTypes, mStatusBarColor, mWindowFlags, forceBarBackground)) {
-                return (int) (mSystemBarInsets.top * mScale);
-            } else {
-                return 0;
-            }
-        }
-
-        private boolean isNavigationBarColorViewVisible() {
-            final boolean forceBarBackground =
-                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
-            return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                    mRequestedVisibleTypes, mNavigationBarColor, mWindowFlags, forceBarBackground);
-        }
-
-        void drawDecors(Canvas c) {
-            drawStatusBarBackground(c, getStatusBarColorViewHeight());
-            drawNavigationBarBackground(c);
-        }
-
-        @VisibleForTesting
-        void drawStatusBarBackground(Canvas c,
-                int statusBarHeight) {
-            if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0) {
-                final int rightInset = (int) (mSystemBarInsets.right * mScale);
-                c.drawRect(0, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
-            }
-        }
-
-        @VisibleForTesting
-        void drawNavigationBarBackground(Canvas c) {
-            final Rect navigationBarRect = new Rect();
-            getNavigationBarRect(c.getWidth(), c.getHeight(), mSystemBarInsets, navigationBarRect,
-                    mScale);
-            final boolean visible = isNavigationBarColorViewVisible();
-            if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
-                c.drawRect(navigationBarRect, mNavigationBarPaint);
-            }
-        }
-    }
 }
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 5e11163..f346b92 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -147,7 +147,7 @@
         if (mApnSetting != null) {
             return mApnSetting.getProtocol();
         }
-        return ApnSetting.PROTOCOL_IP;
+        return ApnSetting.PROTOCOL_IPV4V6;
     }
 
     /**