Merge "Revert "Revert "Revert "Revert "SharedMemory: break Cleaner reference cycle.""""" into sc-v2-dev
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 19a1d7a..45df0d9 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1294,8 +1294,11 @@
         }
 
         @Override
-        public void scheduleCrash(String msg, int typeId) {
-            sendMessage(H.SCHEDULE_CRASH, msg, typeId);
+        public void scheduleCrash(String msg, int typeId, @Nullable Bundle extras) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = msg;
+            args.arg2 = extras;
+            sendMessage(H.SCHEDULE_CRASH, args, typeId);
         }
 
         public void dumpActivity(ParcelFileDescriptor pfd, IBinder activitytoken,
@@ -1925,11 +1928,11 @@
         }
     }
 
-    private void throwRemoteServiceException(String message, int typeId) {
+    private void throwRemoteServiceException(String message, int typeId, @Nullable Bundle extras) {
         // Use a switch to ensure all the type IDs are unique.
         switch (typeId) {
             case ForegroundServiceDidNotStartInTimeException.TYPE_ID:
-                throw new ForegroundServiceDidNotStartInTimeException(message);
+                throw generateForegroundServiceDidNotStartInTimeException(message, extras);
 
             case CannotDeliverBroadcastException.TYPE_ID:
                 throw new CannotDeliverBroadcastException(message);
@@ -1952,6 +1955,15 @@
         }
     }
 
+    private ForegroundServiceDidNotStartInTimeException
+            generateForegroundServiceDidNotStartInTimeException(String message, Bundle extras) {
+        final String serviceClassName =
+                ForegroundServiceDidNotStartInTimeException.getServiceClassNameFromExtras(extras);
+        final Exception inner = (serviceClassName == null) ? null
+                : Service.getStartForegroundServiceStackTrace(serviceClassName);
+        throw new ForegroundServiceDidNotStartInTimeException(message, inner);
+    }
+
     class H extends Handler {
         public static final int BIND_APPLICATION        = 110;
         @UnsupportedAppUsage
@@ -2169,9 +2181,14 @@
                     handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj);
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
-                case SCHEDULE_CRASH:
-                    throwRemoteServiceException((String) msg.obj, msg.arg1);
+                case SCHEDULE_CRASH: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    String message = (String) args.arg1;
+                    Bundle extras = (Bundle) args.arg2;
+                    args.recycle();
+                    throwRemoteServiceException(message, msg.arg1, extras);
                     break;
+                }
                 case DUMP_HEAP:
                     handleDumpHeap((DumpHeapData) msg.obj);
                     break;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index e76c139..db3c7d9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1862,6 +1862,14 @@
                             "Not allowed to start service " + service + ": " + cn.getClassName());
                 }
             }
+            // If we started a foreground service in the same package, remember the stack trace.
+            if (cn != null && requireForeground) {
+                if (cn.getPackageName().equals(getOpPackageName())) {
+                    Service.setStartForegroundServiceStackTrace(cn.getClassName(),
+                            new StackTrace("Last startServiceCommon() call for this service was "
+                                    + "made here"));
+                }
+            }
             return cn;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 4912703..64a9c44 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -321,6 +321,8 @@
     boolean isTopActivityImmersive();
     void crashApplicationWithType(int uid, int initialPid, in String packageName, int userId,
             in String message, boolean force, int exceptionTypeId);
+    void crashApplicationWithTypeWithExtras(int uid, int initialPid, in String packageName,
+            int userId, in String message, boolean force, int exceptionTypeId, in Bundle extras);
     /** @deprecated -- use getProviderMimeTypeAsync */
     @UnsupportedAppUsage(maxTargetSdk = 29, publicAlternatives =
             "Use {@link android.content.ContentResolver#getType} public API instead.")
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index d6ff6d3..448c3cf 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -107,7 +107,7 @@
     void scheduleOnNewActivityOptions(IBinder token, in Bundle options);
     void scheduleSuicide();
     void dispatchPackageBroadcast(int cmd, in String[] packages);
-    void scheduleCrash(in String msg, int typeId);
+    void scheduleCrash(in String msg, int typeId, in Bundle extras);
     void dumpHeap(boolean managed, boolean mallocInfo, boolean runGc, in String path,
             in ParcelFileDescriptor fd, in RemoteCallback finishCallback);
     void dumpActivity(in ParcelFileDescriptor fd, IBinder servicetoken, in String prefix,
diff --git a/core/java/android/app/RemoteServiceException.java b/core/java/android/app/RemoteServiceException.java
index 1038530..e220627 100644
--- a/core/java/android/app/RemoteServiceException.java
+++ b/core/java/android/app/RemoteServiceException.java
@@ -16,6 +16,10 @@
 
 package android.app;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.os.Bundle;
 import android.util.AndroidRuntimeException;
 
 /**
@@ -33,6 +37,10 @@
         super(msg);
     }
 
+    public RemoteServiceException(String msg, Throwable cause) {
+        super(msg, cause);
+    }
+
     /**
      * Exception used to crash an app process when it didn't call {@link Service#startForeground}
      * in time after the service was started with
@@ -44,8 +52,21 @@
         /** The type ID passed to {@link IApplicationThread#scheduleCrash}. */
         public static final int TYPE_ID = 1;
 
-        public ForegroundServiceDidNotStartInTimeException(String msg) {
-            super(msg);
+        private static final String KEY_SERVICE_CLASS_NAME = "serviceclassname";
+
+        public ForegroundServiceDidNotStartInTimeException(String msg, Throwable cause) {
+            super(msg, cause);
+        }
+
+        public static Bundle createExtrasForService(@NonNull ComponentName service) {
+            Bundle b = new Bundle();
+            b.putString(KEY_SERVICE_CLASS_NAME, service.getClassName());
+            return b;
+        }
+
+        @Nullable
+        public static String getServiceClassNameFromExtras(@Nullable Bundle extras) {
+            return (extras == null) ? null : extras.getString(KEY_SERVICE_CLASS_NAME);
         }
     }
 
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 3363872..5a5ccb5 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -33,9 +33,12 @@
 import android.os.Build;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.ArrayMap;
 import android.util.Log;
 import android.view.contentcapture.ContentCaptureManager;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -733,6 +736,7 @@
             mActivityManager.setServiceForeground(
                     new ComponentName(this, mClassName), mToken, id,
                     notification, 0, FOREGROUND_SERVICE_TYPE_MANIFEST);
+            clearStartForegroundServiceStackTrace();
         } catch (RemoteException ex) {
         }
     }
@@ -786,6 +790,7 @@
             mActivityManager.setServiceForeground(
                     new ComponentName(this, mClassName), mToken, id,
                     notification, 0, foregroundServiceType);
+            clearStartForegroundServiceStackTrace();
         } catch (RemoteException ex) {
         }
     }
@@ -941,4 +946,34 @@
     private IActivityManager mActivityManager = null;
     @UnsupportedAppUsage
     private boolean mStartCompatibility = false;
+
+    /**
+     * This keeps track of the stacktrace where Context.startForegroundService() was called
+     * for each service class. We use that when we crash the app for not calling
+     * {@link #startForeground} in time, in {@link ActivityThread#throwRemoteServiceException}.
+     */
+    @GuardedBy("sStartForegroundServiceStackTraces")
+    private static final ArrayMap<String, StackTrace> sStartForegroundServiceStackTraces =
+            new ArrayMap<>();
+
+    /** @hide */
+    public static void setStartForegroundServiceStackTrace(
+            @NonNull String className, @NonNull StackTrace stacktrace) {
+        synchronized (sStartForegroundServiceStackTraces) {
+            sStartForegroundServiceStackTraces.put(className, stacktrace);
+        }
+    }
+
+    private void clearStartForegroundServiceStackTrace() {
+        synchronized (sStartForegroundServiceStackTraces) {
+            sStartForegroundServiceStackTraces.remove(this.getClassName());
+        }
+    }
+
+    /** @hide */
+    public static StackTrace getStartForegroundServiceStackTrace(@NonNull String className) {
+        synchronized (sStartForegroundServiceStackTraces) {
+            return sStartForegroundServiceStackTraces.get(className);
+        }
+    }
 }
diff --git a/core/java/android/hardware/devicestate/DeviceStateManagerInternal.java b/core/java/android/app/StackTrace.java
similarity index 65%
rename from core/java/android/hardware/devicestate/DeviceStateManagerInternal.java
rename to core/java/android/app/StackTrace.java
index 4c91c16..ec058f8 100644
--- a/core/java/android/hardware/devicestate/DeviceStateManagerInternal.java
+++ b/core/java/android/app/StackTrace.java
@@ -14,15 +14,14 @@
  * limitations under the License.
  */
 
-package android.hardware.devicestate;
+package android.app;
 
 /**
- * Device state manager local system service interface.
- *
- * @hide Only for use within the system server.
+ * An Exception subclass that's used only for logging stacktraces.
+ * @hide
  */
-public abstract class DeviceStateManagerInternal {
-
-    /** Returns the list of currently supported device state identifiers. */
-    public abstract int[] getSupportedStateIdentifiers();
+public class StackTrace extends Exception {
+    public StackTrace(String message) {
+        super(message);
+    }
 }
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 5bb51c1..4f20553 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -35,7 +35,6 @@
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 import java.util.Objects;
-import java.util.Set;
 
 /**
  * Display manager local system service interface.
@@ -130,14 +129,6 @@
     public abstract DisplayInfo getDisplayInfo(int displayId);
 
     /**
-     * Returns a set of DisplayInfo, for the states that may be assumed by either the given display,
-     * or any other display within that display's group.
-     *
-     * @param displayId The logical display id to fetch DisplayInfo for.
-     */
-    public abstract Set<DisplayInfo> getPossibleDisplayInfo(int displayId);
-
-    /**
      * Returns the position of the display's projection.
      *
      * @param displayId The logical display id.
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 7631269..0fc6b08 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -374,8 +374,8 @@
             currentDisplayInfo = possibleDisplayInfos.get(i);
 
             // Calculate max bounds for this rotation and state.
-            Rect maxBounds = new Rect(0, 0, currentDisplayInfo.logicalWidth,
-                    currentDisplayInfo.logicalHeight);
+            Rect maxBounds = new Rect(0, 0, currentDisplayInfo.getNaturalWidth(),
+                    currentDisplayInfo.getNaturalHeight());
 
             // Calculate insets for the rotated max bounds.
             // TODO(181127261) calculate insets for each display rotation and state.
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index df0c64c..9f48c06 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -532,7 +532,7 @@
         }
 
         @Override
-        public void scheduleCrash(String s, int i) throws RemoteException {
+        public void scheduleCrash(String s, int i, Bundle extras) throws RemoteException {
         }
 
         @Override
diff --git a/libs/WindowManager/Shell/OWNERS b/libs/WindowManager/Shell/OWNERS
deleted file mode 100644
index e2c67fd..0000000
--- a/libs/WindowManager/Shell/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-# sysui owners
-hwwang@google.com
-winsonc@google.com
-madym@google.com
diff --git a/libs/WindowManager/Shell/res/color/taskbar_background.xml b/libs/WindowManager/Shell/res/color/taskbar_background.xml
new file mode 100644
index 0000000..329e5b9
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/taskbar_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@android:color/system_neutral1_500" android:lStar="35" />
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS
new file mode 100644
index 0000000..4d9b520
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/apppairs/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-modules apppair owner
+chenghsiuchang@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS
new file mode 100644
index 0000000..8271014
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-module bubble owner
+madym@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 6b62204..9500e8a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -56,6 +56,7 @@
 import com.android.wm.shell.common.annotations.ShellSplashscreenThread;
 import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
 import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
+import com.android.wm.shell.draganddrop.DragAndDrop;
 import com.android.wm.shell.draganddrop.DragAndDropController;
 import com.android.wm.shell.freeform.FreeformTaskListener;
 import com.android.wm.shell.fullscreen.FullscreenTaskListener;
@@ -156,8 +157,16 @@
     @WMSingleton
     @Provides
     static DragAndDropController provideDragAndDropController(Context context,
-            DisplayController displayController, UiEventLogger uiEventLogger) {
-        return new DragAndDropController(context, displayController, uiEventLogger);
+            DisplayController displayController, UiEventLogger uiEventLogger,
+            IconProvider iconProvider, @ShellMainThread ShellExecutor mainExecutor) {
+        return new DragAndDropController(context, displayController, uiEventLogger, iconProvider,
+                mainExecutor);
+    }
+
+    @WMSingleton
+    @Provides
+    static DragAndDrop provideDragAndDrop(DragAndDropController dragAndDropController) {
+        return dragAndDropController.asDragAndDrop();
     }
 
     @WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java
new file mode 100644
index 0000000..edeff6e3
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop;
+
+import android.content.res.Configuration;
+
+import com.android.wm.shell.common.annotations.ExternalThread;
+
+/**
+ * Interface for telling DragAndDrop stuff.
+ */
+@ExternalThread
+public interface DragAndDrop {
+
+    /** Called when the theme changes. */
+    void onThemeChanged();
+
+    /** Called when the configuration changes. */
+    void onConfigChanged(Configuration newConfig);
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index d2b4711..101295d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -41,7 +41,6 @@
 import android.graphics.PixelFormat;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.view.Display;
 import android.view.DragEvent;
 import android.view.LayoutInflater;
 import android.view.SurfaceControl;
@@ -53,8 +52,10 @@
 import com.android.internal.logging.InstanceId;
 import com.android.internal.logging.UiEventLogger;
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
@@ -71,16 +72,26 @@
     private final Context mContext;
     private final DisplayController mDisplayController;
     private final DragAndDropEventLogger mLogger;
+    private final IconProvider mIconProvider;
     private SplitScreenController mSplitScreen;
+    private ShellExecutor mMainExecutor;
+    private DragAndDropImpl mImpl;
 
     private final SparseArray<PerDisplay> mDisplayDropTargets = new SparseArray<>();
     private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
 
     public DragAndDropController(Context context, DisplayController displayController,
-            UiEventLogger uiEventLogger) {
+            UiEventLogger uiEventLogger, IconProvider iconProvider, ShellExecutor mainExecutor) {
         mContext = context;
         mDisplayController = displayController;
         mLogger = new DragAndDropEventLogger(uiEventLogger);
+        mIconProvider = iconProvider;
+        mMainExecutor = mainExecutor;
+        mImpl = new DragAndDropImpl();
+    }
+
+    public DragAndDrop asDragAndDrop() {
+        return mImpl;
     }
 
     public void initialize(Optional<SplitScreenController> splitscreen) {
@@ -117,7 +128,7 @@
                 R.layout.global_drop_target, null);
         rootView.setOnDragListener(this);
         rootView.setVisibility(View.INVISIBLE);
-        DragLayout dragLayout = new DragLayout(context, mSplitScreen);
+        DragLayout dragLayout = new DragLayout(context, mSplitScreen, mIconProvider);
         rootView.addView(dragLayout,
                 new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
         try {
@@ -267,6 +278,18 @@
         return mimeTypes;
     }
 
+    private void onThemeChange() {
+        for (int i = 0; i < mDisplayDropTargets.size(); i++) {
+            mDisplayDropTargets.get(i).dragLayout.onThemeChange();
+        }
+    }
+
+    private void onConfigChanged(Configuration newConfig) {
+        for (int i = 0; i < mDisplayDropTargets.size(); i++) {
+            mDisplayDropTargets.get(i).dragLayout.onConfigChanged(newConfig);
+        }
+    }
+
     private static class PerDisplay {
         final int displayId;
         final Context context;
@@ -287,4 +310,21 @@
             dragLayout = dl;
         }
     }
+
+    private class DragAndDropImpl implements DragAndDrop {
+
+        @Override
+        public void onThemeChanged() {
+            mMainExecutor.execute(() -> {
+                DragAndDropController.this.onThemeChange();
+            });
+        }
+
+        @Override
+        public void onConfigChanged(Configuration newConfig) {
+            mMainExecutor.execute(() -> {
+                DragAndDropController.this.onConfigChanged(newConfig);
+            });
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
index efc9ed0..20d8054 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragLayout.java
@@ -16,78 +16,138 @@
 
 package com.android.wm.shell.draganddrop;
 
-import static com.android.wm.shell.animation.Interpolators.FAST_OUT_LINEAR_IN;
-import static com.android.wm.shell.animation.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.wm.shell.animation.Interpolators.LINEAR;
-import static com.android.wm.shell.animation.Interpolators.LINEAR_OUT_SLOW_IN;
+import static android.app.StatusBarManager.DISABLE_NONE;
+
+import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.StatusBarManager;
 import android.content.ClipData;
 import android.content.Context;
-import android.graphics.Canvas;
+import android.content.res.Configuration;
+import android.graphics.Color;
 import android.graphics.Insets;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.os.RemoteException;
 import android.view.DragEvent;
 import android.view.SurfaceControl;
-import android.view.View;
+import android.view.ViewGroup;
 import android.view.WindowInsets;
 import android.view.WindowInsets.Type;
-
-import androidx.annotation.NonNull;
+import android.widget.LinearLayout;
 
 import com.android.internal.logging.InstanceId;
 import com.android.internal.protolog.common.ProtoLog;
+import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Coordinates the visible drop targets for the current drag.
  */
-public class DragLayout extends View {
+public class DragLayout extends LinearLayout {
+
+    // While dragging the status bar is hidden.
+    private static final int HIDE_STATUS_BAR_FLAGS = StatusBarManager.DISABLE_NOTIFICATION_ICONS
+            | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
+            | StatusBarManager.DISABLE_CLOCK
+            | StatusBarManager.DISABLE_SYSTEM_INFO;
 
     private final DragAndDropPolicy mPolicy;
+    private final SplitScreenController mSplitScreenController;
+    private final IconProvider mIconProvider;
+    private final StatusBarManager mStatusBarManager;
 
     private DragAndDropPolicy.Target mCurrentTarget = null;
-    private DropOutlineDrawable mDropOutline;
+    private DropZoneView mDropZoneView1;
+    private DropZoneView mDropZoneView2;
+
     private int mDisplayMargin;
     private Insets mInsets = Insets.NONE;
 
     private boolean mIsShowing;
     private boolean mHasDropped;
 
-    public DragLayout(Context context, SplitScreenController splitscreen) {
+    @SuppressLint("WrongConstant")
+    public DragLayout(Context context, SplitScreenController splitScreenController,
+            IconProvider iconProvider) {
         super(context);
-        mPolicy = new DragAndDropPolicy(context, splitscreen);
+        mSplitScreenController = splitScreenController;
+        mIconProvider = iconProvider;
+        mPolicy = new DragAndDropPolicy(context, splitScreenController);
+        mStatusBarManager = context.getSystemService(StatusBarManager.class);
+
         mDisplayMargin = context.getResources().getDimensionPixelSize(
                 R.dimen.drop_layout_display_margin);
-        mDropOutline = new DropOutlineDrawable(context);
-        setBackground(mDropOutline);
-        setWillNotDraw(false);
+
+        mDropZoneView1 = new DropZoneView(context);
+        mDropZoneView2 = new DropZoneView(context);
+        addView(mDropZoneView1, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+        addView(mDropZoneView2, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+        ((LayoutParams) mDropZoneView1.getLayoutParams()).weight = 1;
+        ((LayoutParams) mDropZoneView2.getLayoutParams()).weight = 1;
+        updateContainerMargins();
     }
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         mInsets = insets.getInsets(Type.systemBars() | Type.displayCutout());
         recomputeDropTargets();
+
+        final int orientation = getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            mDropZoneView1.setBottomInset(mInsets.bottom);
+            mDropZoneView2.setBottomInset(mInsets.bottom);
+        } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+            mDropZoneView1.setBottomInset(0);
+            mDropZoneView2.setBottomInset(mInsets.bottom);
+        }
         return super.onApplyWindowInsets(insets);
     }
 
-    @Override
-    protected boolean verifyDrawable(@NonNull Drawable who) {
-        return who == mDropOutline || super.verifyDrawable(who);
+    public void onThemeChange() {
+        mDropZoneView1.onThemeChange();
+        mDropZoneView2.onThemeChange();
     }
 
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mCurrentTarget != null) {
-            mDropOutline.draw(canvas);
+    public void onConfigChanged(Configuration newConfig) {
+        final int orientation = getResources().getConfiguration().orientation;
+        if (orientation == Configuration.ORIENTATION_LANDSCAPE
+                && getOrientation() != HORIZONTAL) {
+            setOrientation(LinearLayout.HORIZONTAL);
+            updateContainerMargins();
+        } else if (orientation == Configuration.ORIENTATION_PORTRAIT
+                && getOrientation() != VERTICAL) {
+            setOrientation(LinearLayout.VERTICAL);
+            updateContainerMargins();
+        }
+    }
+
+    private void updateContainerMargins() {
+        final int orientation = getResources().getConfiguration().orientation;
+        final float halfMargin = mDisplayMargin / 2f;
+        if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
+            mDropZoneView1.setContainerMargin(
+                    mDisplayMargin, mDisplayMargin, halfMargin, mDisplayMargin);
+            mDropZoneView2.setContainerMargin(
+                    halfMargin, mDisplayMargin, mDisplayMargin, mDisplayMargin);
+        } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+            mDropZoneView1.setContainerMargin(
+                    mDisplayMargin, mDisplayMargin, mDisplayMargin, halfMargin);
+            mDropZoneView2.setContainerMargin(
+                    mDisplayMargin, halfMargin, mDisplayMargin, mDisplayMargin);
         }
     }
 
@@ -104,6 +164,43 @@
         mPolicy.start(displayLayout, initialData, loggerSessionId);
         mHasDropped = false;
         mCurrentTarget = null;
+
+        List<ActivityManager.RunningTaskInfo> tasks = null;
+        // Figure out the splashscreen info for the existing task(s).
+        try {
+            tasks = ActivityTaskManager.getService().getTasks(2,
+                            false /* filterOnlyVisibleRecents */,
+                            false /* keepIntentExtra */);
+        } catch (RemoteException e) {
+            // don't show an icon / will just use the defaults
+        }
+        if (tasks != null && !tasks.isEmpty()) {
+            ActivityManager.RunningTaskInfo taskInfo1 = tasks.get(0);
+            Drawable icon1 = mIconProvider.getIcon(taskInfo1.topActivityInfo);
+            int bgColor1 = getResizingBackgroundColor(taskInfo1);
+
+            boolean alreadyInSplit = mSplitScreenController != null
+                    && mSplitScreenController.isSplitScreenVisible();
+            if (alreadyInSplit && tasks.size() > 1) {
+                ActivityManager.RunningTaskInfo taskInfo2 = tasks.get(1);
+                Drawable icon2 = mIconProvider.getIcon(taskInfo2.topActivityInfo);
+                int bgColor2 = getResizingBackgroundColor(taskInfo2);
+
+                // figure out which task is on which side
+                int splitPosition1 = mSplitScreenController.getSplitPosition(taskInfo1.taskId);
+                boolean isTask1TopOrLeft = splitPosition1 == SPLIT_POSITION_TOP_OR_LEFT;
+                if (isTask1TopOrLeft) {
+                    mDropZoneView1.setAppInfo(bgColor1, icon1);
+                    mDropZoneView2.setAppInfo(bgColor2, icon2);
+                } else {
+                    mDropZoneView2.setAppInfo(bgColor1, icon1);
+                    mDropZoneView1.setAppInfo(bgColor2, icon2);
+                }
+            } else {
+                mDropZoneView1.setAppInfo(bgColor1, icon1);
+                mDropZoneView2.setAppInfo(bgColor1, icon1);
+            }
+        }
     }
 
     public void show() {
@@ -139,20 +236,14 @@
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DRAG_AND_DROP, "Current target: %s", target);
             if (target == null) {
                 // Animating to no target
-                mDropOutline.startVisibilityAnimation(false, LINEAR);
-                Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
-                finalBounds.inset(mDisplayMargin, mDisplayMargin);
-                mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
+                animateSplitContainers(false, null /* animCompleteCallback */);
             } else if (mCurrentTarget == null) {
                 // Animating to first target
-                mDropOutline.startVisibilityAnimation(true, LINEAR);
-                Rect initialBounds = new Rect(target.drawRegion);
-                initialBounds.inset(mDisplayMargin, mDisplayMargin);
-                mDropOutline.setRegionBounds(initialBounds);
-                mDropOutline.startBoundsAnimation(target.drawRegion, LINEAR_OUT_SLOW_IN);
+                animateSplitContainers(true, null /* animCompleteCallback */);
+                animateHighlight(target);
             } else {
-                // Bounds change
-                mDropOutline.startBoundsAnimation(target.drawRegion, FAST_OUT_SLOW_IN);
+                // Switching between targets
+                animateHighlight(target);
             }
             mCurrentTarget = target;
         }
@@ -163,26 +254,7 @@
      */
     public void hide(DragEvent event, Runnable hideCompleteCallback) {
         mIsShowing = false;
-        ObjectAnimator alphaAnimator = mDropOutline.startVisibilityAnimation(false, LINEAR);
-        ObjectAnimator boundsAnimator = null;
-        if (mCurrentTarget != null) {
-            Rect finalBounds = new Rect(mCurrentTarget.drawRegion);
-            finalBounds.inset(mDisplayMargin, mDisplayMargin);
-            boundsAnimator = mDropOutline.startBoundsAnimation(finalBounds, FAST_OUT_LINEAR_IN);
-        }
-
-        if (hideCompleteCallback != null) {
-            ObjectAnimator lastAnim = boundsAnimator != null
-                    ? boundsAnimator
-                    : alphaAnimator;
-            lastAnim.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    hideCompleteCallback.run();
-                }
-            });
-        }
-
+        animateSplitContainers(false, hideCompleteCallback);
         mCurrentTarget = null;
     }
 
@@ -201,4 +273,49 @@
         hide(event, dropCompleteCallback);
         return handledDrop;
     }
+
+    private void animateSplitContainers(boolean visible, Runnable animCompleteCallback) {
+        mStatusBarManager.disable(visible
+                ? HIDE_STATUS_BAR_FLAGS
+                : DISABLE_NONE);
+        mDropZoneView1.setShowingMargin(visible);
+        mDropZoneView2.setShowingMargin(visible);
+        ObjectAnimator animator = mDropZoneView1.getAnimator();
+        if (animCompleteCallback != null) {
+            if (animator != null) {
+                animator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        animCompleteCallback.run();
+                    }
+                });
+            } else {
+                // If there's no animator the animation is done so run immediately
+                animCompleteCallback.run();
+            }
+        }
+    }
+
+    private void animateHighlight(DragAndDropPolicy.Target target) {
+        if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_LEFT
+                || target.type == DragAndDropPolicy.Target.TYPE_SPLIT_TOP) {
+            mDropZoneView1.setShowingHighlight(true);
+            mDropZoneView1.setShowingSplash(false);
+
+            mDropZoneView2.setShowingHighlight(false);
+            mDropZoneView2.setShowingSplash(true);
+        } else if (target.type == DragAndDropPolicy.Target.TYPE_SPLIT_RIGHT
+                || target.type == DragAndDropPolicy.Target.TYPE_SPLIT_BOTTOM) {
+            mDropZoneView1.setShowingHighlight(false);
+            mDropZoneView1.setShowingSplash(true);
+
+            mDropZoneView2.setShowingHighlight(true);
+            mDropZoneView2.setShowingSplash(false);
+        }
+    }
+
+    private static int getResizingBackgroundColor(ActivityManager.RunningTaskInfo taskInfo) {
+        final int taskBgColor = taskInfo.taskDescription.getBackgroundColor();
+        return Color.valueOf(taskBgColor == -1 ? Color.WHITE : taskBgColor).toArgb();
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
new file mode 100644
index 0000000..2f47af5
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.draganddrop;
+
+import static com.android.wm.shell.animation.Interpolators.FAST_OUT_SLOW_IN;
+
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Path;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.FloatProperty;
+import android.util.IntProperty;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.policy.ScreenDecorationsUtils;
+import com.android.wm.shell.R;
+
+/**
+ * Renders a drop zone area for items being dragged.
+ */
+public class DropZoneView extends FrameLayout {
+
+    private static final int SPLASHSCREEN_ALPHA_INT = (int) (255 * 0.90f);
+    private static final int HIGHLIGHT_ALPHA_INT = 255;
+    private static final int MARGIN_ANIMATION_ENTER_DURATION = 400;
+    private static final int MARGIN_ANIMATION_EXIT_DURATION = 250;
+
+    private static final FloatProperty<DropZoneView> INSETS =
+            new FloatProperty<DropZoneView>("insets") {
+                @Override
+                public void setValue(DropZoneView v, float percent) {
+                    v.setMarginPercent(percent);
+                }
+
+                @Override
+                public Float get(DropZoneView v) {
+                    return v.getMarginPercent();
+                }
+            };
+
+    private static final IntProperty<ColorDrawable> SPLASHSCREEN_ALPHA =
+            new IntProperty<ColorDrawable>("splashscreen") {
+                @Override
+                public void setValue(ColorDrawable d, int alpha) {
+                    d.setAlpha(alpha);
+                }
+
+                @Override
+                public Integer get(ColorDrawable d) {
+                    return d.getAlpha();
+                }
+            };
+
+    private static final IntProperty<ColorDrawable> HIGHLIGHT_ALPHA =
+            new IntProperty<ColorDrawable>("highlight") {
+                @Override
+                public void setValue(ColorDrawable d, int alpha) {
+                    d.setAlpha(alpha);
+                }
+
+                @Override
+                public Integer get(ColorDrawable d) {
+                    return d.getAlpha();
+                }
+            };
+
+    private final Path mPath = new Path();
+    private final float[] mContainerMargin = new float[4];
+    private float mCornerRadius;
+    private float mBottomInset;
+    private int mMarginColor; // i.e. color used for negative space like the container insets
+    private int mHighlightColor;
+
+    private boolean mShowingHighlight;
+    private boolean mShowingSplash;
+    private boolean mShowingMargin;
+
+    // TODO: might be more seamless to animate between splash/highlight color instead of 2 separate
+    private ObjectAnimator mSplashAnimator;
+    private ObjectAnimator mHighlightAnimator;
+    private ObjectAnimator mMarginAnimator;
+    private float mMarginPercent;
+
+    // Renders a highlight or neutral transparent color
+    private ColorDrawable mDropZoneDrawable;
+    // Renders the translucent splashscreen with the app icon in the middle
+    private ImageView mSplashScreenView;
+    private ColorDrawable mSplashBackgroundDrawable;
+    // Renders the margin / insets around the dropzone container
+    private MarginView mMarginView;
+
+    public DropZoneView(Context context) {
+        this(context, null);
+    }
+
+    public DropZoneView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public DropZoneView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public DropZoneView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        setContainerMargin(0, 0, 0, 0); // make sure it's populated
+
+        mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
+        mMarginColor = getResources().getColor(R.color.taskbar_background);
+        mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
+
+        mDropZoneDrawable = new ColorDrawable();
+        mDropZoneDrawable.setColor(mHighlightColor);
+        mDropZoneDrawable.setAlpha(0);
+        setBackgroundDrawable(mDropZoneDrawable);
+
+        mSplashScreenView = new ImageView(context);
+        mSplashScreenView.setScaleType(ImageView.ScaleType.CENTER);
+        mSplashBackgroundDrawable = new ColorDrawable();
+        mSplashBackgroundDrawable.setColor(Color.WHITE);
+        mSplashBackgroundDrawable.setAlpha(SPLASHSCREEN_ALPHA_INT);
+        mSplashScreenView.setBackgroundDrawable(mSplashBackgroundDrawable);
+        addView(mSplashScreenView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+        mSplashScreenView.setAlpha(0f);
+
+        mMarginView = new MarginView(context);
+        addView(mMarginView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+    }
+
+    public void onThemeChange() {
+        mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(getContext());
+        mMarginColor = getResources().getColor(R.color.taskbar_background);
+        mHighlightColor = getResources().getColor(android.R.color.system_accent1_500);
+
+        final int alpha = mDropZoneDrawable.getAlpha();
+        mDropZoneDrawable.setColor(mHighlightColor);
+        mDropZoneDrawable.setAlpha(alpha);
+
+        if (mMarginPercent > 0) {
+            mMarginView.invalidate();
+        }
+    }
+
+    /** Sets the desired margins around the drop zone container when fully showing. */
+    public void setContainerMargin(float left, float top, float right, float bottom) {
+        mContainerMargin[0] = left;
+        mContainerMargin[1] = top;
+        mContainerMargin[2] = right;
+        mContainerMargin[3] = bottom;
+        if (mMarginPercent > 0) {
+            mMarginView.invalidate();
+        }
+    }
+
+    /** Sets the bottom inset so the drop zones are above bottom navigation. */
+    public void setBottomInset(float bottom) {
+        mBottomInset = bottom;
+        ((LayoutParams) mSplashScreenView.getLayoutParams()).bottomMargin = (int) bottom;
+        if (mMarginPercent > 0) {
+            mMarginView.invalidate();
+        }
+    }
+
+    /** Sets the color and icon to use for the splashscreen when shown. */
+    public void setAppInfo(int splashScreenColor, Drawable appIcon) {
+        mSplashBackgroundDrawable.setColor(splashScreenColor);
+        mSplashScreenView.setImageDrawable(appIcon);
+    }
+
+    /** @return an active animator for this view if one exists. */
+    @Nullable
+    public ObjectAnimator getAnimator() {
+        if (mMarginAnimator != null && mMarginAnimator.isRunning()) {
+            return mMarginAnimator;
+        } else if (mHighlightAnimator != null && mHighlightAnimator.isRunning()) {
+            return mHighlightAnimator;
+        } else if (mSplashAnimator != null && mSplashAnimator.isRunning()) {
+            return mSplashAnimator;
+        }
+        return null;
+    }
+
+    /** Animates the splashscreen to show or hide. */
+    public void setShowingSplash(boolean showingSplash) {
+        if (mShowingSplash != showingSplash) {
+            mShowingSplash = showingSplash;
+            animateSplashToState();
+        }
+    }
+
+    /** Animates the highlight indicating the zone is hovered on or not. */
+    public void setShowingHighlight(boolean showingHighlight) {
+        if (mShowingHighlight != showingHighlight) {
+            mShowingHighlight = showingHighlight;
+            animateHighlightToState();
+        }
+    }
+
+    /** Animates the margins around the drop zone to show or hide. */
+    public void setShowingMargin(boolean visible) {
+        if (mShowingMargin != visible) {
+            mShowingMargin = visible;
+            animateMarginToState();
+        }
+        if (!mShowingMargin) {
+            setShowingHighlight(false);
+            setShowingSplash(false);
+        }
+    }
+
+    private void animateSplashToState() {
+        if (mSplashAnimator != null) {
+            mSplashAnimator.cancel();
+        }
+        mSplashAnimator = ObjectAnimator.ofInt(mSplashBackgroundDrawable,
+                SPLASHSCREEN_ALPHA,
+                mSplashBackgroundDrawable.getAlpha(),
+                mShowingSplash ? SPLASHSCREEN_ALPHA_INT : 0);
+        if (!mShowingSplash) {
+            mSplashAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+        }
+        mSplashAnimator.start();
+        mSplashScreenView.animate().alpha(mShowingSplash ? 1f : 0f).start();
+    }
+
+    private void animateHighlightToState() {
+        if (mHighlightAnimator != null) {
+            mHighlightAnimator.cancel();
+        }
+        mHighlightAnimator = ObjectAnimator.ofInt(mDropZoneDrawable,
+                HIGHLIGHT_ALPHA,
+                mDropZoneDrawable.getAlpha(),
+                mShowingHighlight ? HIGHLIGHT_ALPHA_INT : 0);
+        if (!mShowingHighlight) {
+            mHighlightAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+        }
+        mHighlightAnimator.start();
+    }
+
+    private void animateMarginToState() {
+        if (mMarginAnimator != null) {
+            mMarginAnimator.cancel();
+        }
+        mMarginAnimator = ObjectAnimator.ofFloat(this, INSETS,
+                mMarginPercent,
+                mShowingMargin ? 1f : 0f);
+        mMarginAnimator.setInterpolator(FAST_OUT_SLOW_IN);
+        mMarginAnimator.setDuration(mShowingMargin
+                ? MARGIN_ANIMATION_ENTER_DURATION
+                : MARGIN_ANIMATION_EXIT_DURATION);
+        mMarginAnimator.start();
+    }
+
+    private void setMarginPercent(float percent) {
+        if (percent != mMarginPercent) {
+            mMarginPercent = percent;
+            mMarginView.invalidate();
+        }
+    }
+
+    private float getMarginPercent() {
+        return mMarginPercent;
+    }
+
+    /** Simple view that draws a rounded rect margin around its contents. **/
+    private class MarginView extends View {
+
+        MarginView(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            mPath.reset();
+            mPath.addRoundRect(mContainerMargin[0] * mMarginPercent,
+                    mContainerMargin[1] * mMarginPercent,
+                    getWidth() - (mContainerMargin[2] * mMarginPercent),
+                    getHeight() - (mContainerMargin[3] * mMarginPercent) - mBottomInset,
+                    mCornerRadius * mMarginPercent,
+                    mCornerRadius * mMarginPercent,
+                    Path.Direction.CW);
+            mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD);
+            canvas.clipPath(mPath);
+            canvas.drawColor(mMarginColor);
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OWNERS
new file mode 100644
index 0000000..41177f0
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-module one handed mode owner
+lbill@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS
new file mode 100644
index 0000000..afddfab
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-module pip owner
+hwwang@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OWNERS
new file mode 100644
index 0000000..7237d2b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-modules splitscreen owner
+chenghsiuchang@google.com
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 262a9a1..d2e341d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -188,6 +188,10 @@
                 && mStageCoordinator.getStageOfTask(taskId) != STAGE_TYPE_UNDEFINED;
     }
 
+    public @SplitPosition int getSplitPosition(int taskId) {
+        return mStageCoordinator.getSplitPosition(taskId);
+    }
+
     public boolean moveToSideStage(int taskId, @SplitPosition int sideStagePosition) {
         return moveToStage(taskId, STAGE_TYPE_SIDE, sideStagePosition,
                 new WindowContainerTransaction());
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index a5579ae..8ad0f20 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -678,6 +678,16 @@
         outBottomOrRightBounds.set(mSplitLayout.getBounds2());
     }
 
+    @SplitPosition
+    int getSplitPosition(int taskId) {
+        if (mSideStage.getTopVisibleChildTaskId() == taskId) {
+            return getSideStagePosition();
+        } else if (mMainStage.getTopVisibleChildTaskId() == taskId) {
+            return getMainStagePosition();
+        }
+        return SPLIT_POSITION_UNDEFINED;
+    }
+
     private void addActivityOptions(Bundle opts, StageTaskListener stage) {
         opts.putParcelable(KEY_LAUNCH_ROOT_TASK_TOKEN, stage.mRootTaskInfo.token);
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OWNERS b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OWNERS
new file mode 100644
index 0000000..264e88f
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/stagesplit/OWNERS
@@ -0,0 +1,2 @@
+# WM shell sub-modules stagesplit owner
+chenghsiuchang@google.com
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
index bfa2c92..9f74520 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java
@@ -30,7 +30,9 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.UiEventLogger;
+import com.android.launcher3.icons.IconProvider;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.ShellExecutor;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -59,8 +61,8 @@
     @Before
     public void setUp() throws RemoteException {
         MockitoAnnotations.initMocks(this);
-
-        mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger);
+        mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger,
+                mock(IconProvider.class), mock(ShellExecutor.class));
     }
 
     @Test
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 9cd7083..c30c742 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -98,6 +98,10 @@
     private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config";
     private static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config";
     private static final String KEY_SIM_SPECIFIC_SETTINGS = "sim_specific_settings";
+    // Restoring sim-specific data backed up from newer Android version to Android 12 was causing a
+    // fatal crash. Creating a backup with a different key will prevent Android 12 versions from
+    // restoring this data.
+    private static final String KEY_SIM_SPECIFIC_SETTINGS_2 = "sim_specific_settings_2";
 
     // Versioning of the state file.  Increment this version
     // number any time the set of state items is altered.
@@ -253,7 +257,7 @@
                         deviceSpecificInformation, data);
         stateChecksums[STATE_SIM_SPECIFIC_SETTINGS] =
                 writeIfChanged(stateChecksums[STATE_SIM_SPECIFIC_SETTINGS],
-                        KEY_SIM_SPECIFIC_SETTINGS, simSpecificSettingsData, data);
+                        KEY_SIM_SPECIFIC_SETTINGS_2, simSpecificSettingsData, data);
 
         writeNewChecksums(stateChecksums, newState);
     }
@@ -395,6 +399,9 @@
                     break;
 
                 case KEY_SIM_SPECIFIC_SETTINGS:
+                    // Intentional fall through so that sim-specific backups from Android 12 will
+                    // also be restored on newer Android versions.
+                case KEY_SIM_SPECIFIC_SETTINGS_2:
                     byte[] restoredSimSpecificSettings = new byte[size];
                     data.readEntityData(restoredSimSpecificSettings, 0, size);
                     restoreSimSpecificSettings(restoredSimSpecificSettings);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index b56d189..ba67716 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -144,7 +144,7 @@
     private static final boolean DEBUG_FACE = Build.IS_DEBUGGABLE;
     private static final boolean DEBUG_FINGERPRINT = Build.IS_DEBUGGABLE;
     private static final boolean DEBUG_SPEW = false;
-    private static final int FINGERPRINT_LOCKOUT_RESET_DELAY_MS = 600;
+    private static final int BIOMETRIC_LOCKOUT_RESET_DELAY_MS = 600;
 
     private static final String ACTION_FACE_UNLOCK_STARTED
             = "com.android.facelock.FACE_UNLOCK_STARTED";
@@ -201,6 +201,19 @@
     private static final int BIOMETRIC_STATE_CANCELLING = 2;
 
     /**
+     * Action indicating keyguard *can* start biometric authentiation.
+     */
+    private static final int BIOMETRIC_ACTION_START = 0;
+    /**
+     * Action indicating keyguard *can* stop biometric authentiation.
+     */
+    private static final int BIOMETRIC_ACTION_STOP = 1;
+    /**
+     * Action indicating keyguard *can* start or stop biometric authentiation.
+     */
+    private static final int BIOMETRIC_ACTION_UPDATE = 2;
+
+    /**
      * Biometric state: During cancelling we got another request to start listening, so when we
      * receive the cancellation done signal, we should start listening again.
      */
@@ -339,13 +352,13 @@
     private final Runnable mFpCancelNotReceived = () -> {
         Log.e(TAG, "Fp cancellation not received, transitioning to STOPPED");
         mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
-        updateFingerprintListeningState();
+        updateFingerprintListeningState(BIOMETRIC_ACTION_STOP);
     };
 
     private final Runnable mFaceCancelNotReceived = () -> {
         Log.e(TAG, "Face cancellation not received, transitioning to STOPPED");
         mFaceRunningState = BIOMETRIC_STATE_STOPPED;
-        updateFaceListeningState();
+        updateFaceListeningState(BIOMETRIC_ACTION_STOP);
     };
 
     private final Handler mHandler;
@@ -365,7 +378,7 @@
                 public void onChanged(boolean enabled, int userId) throws RemoteException {
                     mHandler.post(() -> {
                         mBiometricEnabledForUser.put(userId, enabled);
-                        updateBiometricListeningState();
+                        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
                     });
                 }
             };
@@ -415,7 +428,6 @@
     private final KeyguardListenQueue mListenModels = new KeyguardListenQueue();
 
     private static int sCurrentUser;
-    private Runnable mUpdateBiometricListeningState = this::updateBiometricListeningState;
 
     public synchronized static void setCurrentUser(int currentUser) {
         sCurrentUser = currentUser;
@@ -428,8 +440,17 @@
     @Override
     public void onTrustChanged(boolean enabled, int userId, int flags) {
         Assert.isMainThread();
+        boolean wasTrusted = mUserHasTrust.get(userId, false);
         mUserHasTrust.put(userId, enabled);
-        updateBiometricListeningState();
+        // If there was no change in trusted state, make sure we are not authenticating.
+        // TrustManager sends an onTrustChanged whenever a user unlocks keyguard, for
+        // this reason we need to make sure to not authenticate.
+        if (wasTrusted == enabled) {
+            updateBiometricListeningState(BIOMETRIC_ACTION_STOP);
+        } else if (!enabled) {
+            updateBiometricListeningState(BIOMETRIC_ACTION_START);
+        }
+
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -594,7 +615,8 @@
      */
     public void setCredentialAttempted() {
         mCredentialAttempted = true;
-        updateBiometricListeningState();
+        // Do not update face listening state in case of false authentication attempts.
+        updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     /**
@@ -602,7 +624,7 @@
      */
     public void setKeyguardGoingAway(boolean goingAway) {
         mKeyguardGoingAway = goingAway;
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     /**
@@ -610,7 +632,7 @@
      */
     public void setKeyguardOccluded(boolean occluded) {
         mKeyguardOccluded = occluded;
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
 
@@ -622,7 +644,7 @@
      */
     public void requestFaceAuthOnOccludingApp(boolean request) {
         mOccludingAppRequestingFace = request;
-        updateFaceListeningState();
+        updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     /**
@@ -633,7 +655,7 @@
      */
     public void requestFingerprintAuthOnOccludingApp(boolean request) {
         mOccludingAppRequestingFp = request;
-        updateFingerprintListeningState();
+        updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     /**
@@ -641,7 +663,7 @@
      */
     public void onCameraLaunched() {
         mSecureCameraLaunched = true;
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     /**
@@ -676,7 +698,7 @@
         }
         // Don't send cancel if authentication succeeds
         mFingerprintCancelSignal = null;
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -772,7 +794,7 @@
             Log.w(TAG, "Retrying fingerprint after HW unavailable, attempt " +
                     mHardwareFingerprintUnavailableRetryCount);
             if (mFpm.isHardwareDetected()) {
-                updateFingerprintListeningState();
+                updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
             } else if (mHardwareFingerprintUnavailableRetryCount < HAL_ERROR_RETRY_MAX) {
                 mHardwareFingerprintUnavailableRetryCount++;
                 mHandler.postDelayed(mRetryFingerprintAuthentication, HAL_ERROR_RETRY_TIMEOUT);
@@ -792,7 +814,7 @@
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
                 && mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
-            updateFingerprintListeningState();
+            updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
         } else {
             setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
         }
@@ -813,7 +835,7 @@
             lockedOutStateChanged |= !mFingerprintLockedOut;
             mFingerprintLockedOut = true;
             if (isUdfpsEnrolled()) {
-                updateFingerprintListeningState();
+                updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
             }
         }
 
@@ -840,10 +862,11 @@
             // that the events will arrive in a particular order. Add a delay here in case
             // an unlock is in progress. In this is a normal unlock the extra delay won't
             // be noticeable.
-            mHandler.postDelayed(this::updateFingerprintListeningState,
-                    FINGERPRINT_LOCKOUT_RESET_DELAY_MS);
+            mHandler.postDelayed(() -> {
+                updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
+            }, BIOMETRIC_LOCKOUT_RESET_DELAY_MS);
         } else {
-            updateFingerprintListeningState();
+            updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
         }
 
         if (changed) {
@@ -887,7 +910,7 @@
         }
         // Don't send cancel if authentication succeeds
         mFaceCancelSignal = null;
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -980,7 +1003,7 @@
         public void run() {
             Log.w(TAG, "Retrying face after HW unavailable, attempt " +
                     mHardwareFaceUnavailableRetryCount);
-            updateFaceListeningState();
+            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
         }
     };
 
@@ -997,7 +1020,7 @@
         if (msgId == FaceManager.FACE_ERROR_CANCELED
                 && mFaceRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING) {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
-            updateFaceListeningState();
+            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
         } else {
             setFaceRunningState(BIOMETRIC_STATE_STOPPED);
         }
@@ -1035,7 +1058,9 @@
         boolean changed = mFaceLockedOutPermanent;
         mFaceLockedOutPermanent = false;
 
-        updateFaceListeningState();
+        mHandler.postDelayed(() -> {
+            updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
+        }, BIOMETRIC_LOCKOUT_RESET_DELAY_MS);
 
         if (changed) {
             notifyLockedOutStateChanged(BiometricSourceType.FACE);
@@ -1288,7 +1313,7 @@
     @VisibleForTesting
     void setAssistantVisible(boolean assistantVisible) {
         mAssistantVisible = assistantVisible;
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     static class DisplayClientState {
@@ -1627,7 +1652,7 @@
     protected void handleStartedWakingUp() {
         Trace.beginSection("KeyguardUpdateMonitor#handleStartedWakingUp");
         Assert.isMainThread();
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -1648,7 +1673,7 @@
             }
         }
         mGoingToSleep = true;
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     protected void handleFinishedGoingToSleep(int arg1) {
@@ -1660,7 +1685,7 @@
                 cb.onFinishedGoingToSleep(arg1);
             }
         }
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     private void handleScreenTurnedOn() {
@@ -1697,7 +1722,7 @@
                 cb.onDreamingStateChanged(mIsDreaming);
             }
         }
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     private void handleUserInfoChanged(int userId) {
@@ -1888,7 +1913,7 @@
                         setAssistantVisible((boolean) msg.obj);
                         break;
                     case MSG_BIOMETRIC_AUTHENTICATION_CONTINUE:
-                        updateBiometricListeningState();
+                        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
                         break;
                     case MSG_DEVICE_POLICY_MANAGER_STATE_CHANGED:
                         updateLogoutEnabled();
@@ -2006,10 +2031,10 @@
 
             @Override
             public void onEnrollmentsChanged() {
-                mainExecutor.execute(() -> updateBiometricListeningState());
+                mainExecutor.execute(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE));
             }
         });
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
         if (mFpm != null) {
             mFpm.addLockoutResetCallback(mFingerprintLockoutResetCallback);
         }
@@ -2123,12 +2148,12 @@
         mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
     }
 
-    private void updateBiometricListeningState() {
-        updateFingerprintListeningState();
-        updateFaceListeningState();
+    private void updateBiometricListeningState(int action) {
+        updateFingerprintListeningState(action);
+        updateFaceListeningState(action);
     }
 
-    private void updateFingerprintListeningState() {
+    private void updateFingerprintListeningState(int action) {
         // If this message exists, we should not authenticate again until this message is
         // consumed by the handler
         if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
@@ -2140,8 +2165,16 @@
         final boolean runningOrRestarting = mFingerprintRunningState == BIOMETRIC_STATE_RUNNING
                 || mFingerprintRunningState == BIOMETRIC_STATE_CANCELLING_RESTARTING;
         if (runningOrRestarting && !shouldListenForFingerprint) {
+            if (action == BIOMETRIC_ACTION_START) {
+                Log.v(TAG, "Ignoring stopListeningForFingerprint()");
+                return;
+            }
             stopListeningForFingerprint();
         } else if (!runningOrRestarting && shouldListenForFingerprint) {
+            if (action == BIOMETRIC_ACTION_STOP) {
+                Log.v(TAG, "Ignoring startListeningForFingerprint()");
+                return;
+            }
             startListeningForFingerprint();
         }
     }
@@ -2170,7 +2203,7 @@
             return;
         }
         mAuthInterruptActive = active;
-        updateFaceListeningState();
+        updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     /**
@@ -2181,7 +2214,7 @@
     public void requestFaceAuth(boolean userInitiatedRequest) {
         if (DEBUG) Log.d(TAG, "requestFaceAuth() userInitiated=" + userInitiatedRequest);
         mIsFaceAuthUserRequested |= userInitiatedRequest;
-        updateFaceListeningState();
+        updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     public boolean isFaceAuthUserRequested() {
@@ -2195,7 +2228,7 @@
         stopListeningForFace();
     }
 
-    private void updateFaceListeningState() {
+    private void updateFaceListeningState(int action) {
         // If this message exists, we should not authenticate again until this message is
         // consumed by the handler
         if (mHandler.hasMessages(MSG_BIOMETRIC_AUTHENTICATION_CONTINUE)) {
@@ -2204,9 +2237,17 @@
         mHandler.removeCallbacks(mRetryFaceAuthentication);
         boolean shouldListenForFace = shouldListenForFace();
         if (mFaceRunningState == BIOMETRIC_STATE_RUNNING && !shouldListenForFace) {
+            if (action == BIOMETRIC_ACTION_START) {
+                Log.v(TAG, "Ignoring stopListeningForFace()");
+                return;
+            }
             mIsFaceAuthUserRequested = false;
             stopListeningForFace();
         } else if (mFaceRunningState != BIOMETRIC_STATE_RUNNING && shouldListenForFace) {
+            if (action == BIOMETRIC_ACTION_STOP) {
+                Log.v(TAG, "Ignoring startListeningForFace()");
+                return;
+            }
             startListeningForFace();
         }
     }
@@ -2414,7 +2455,7 @@
         mLockIconPressed = true;
         final int userId = getCurrentUser();
         mUserFaceAuthenticated.put(userId, null);
-        updateFaceListeningState();
+        updateFaceListeningState(BIOMETRIC_ACTION_UPDATE);
         mStrongAuthTracker.onStrongAuthRequiredChanged(userId);
     }
 
@@ -2590,7 +2631,7 @@
      */
     private void handleDevicePolicyManagerStateChanged(int userId) {
         Assert.isMainThread();
-        updateFingerprintListeningState();
+        updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
         updateSecondaryLockscreenRequirement(userId);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -2880,7 +2921,7 @@
                 cb.onKeyguardVisibilityChangedRaw(showing);
             }
         }
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     /** Notifies that the occluded state changed. */
@@ -2902,7 +2943,7 @@
      */
     private void handleKeyguardReset() {
         if (DEBUG) Log.d(TAG, "handleKeyguardReset");
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
         mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
     }
 
@@ -2948,7 +2989,7 @@
                 cb.onKeyguardBouncerChanged(mBouncer);
             }
         }
-        updateBiometricListeningState();
+        updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
     }
 
     /**
@@ -3068,7 +3109,9 @@
     public void setSwitchingUser(boolean switching) {
         mSwitchingUser = switching;
         // Since this comes in on a binder thread, we need to post if first
-        mHandler.post(mUpdateBiometricListeningState);
+        mHandler.post(() -> {
+            updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE);
+        });
     }
 
     private void sendUpdates(KeyguardUpdateMonitorCallback callback) {
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index d37dcaf..bb0e79f 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -121,7 +121,8 @@
                     .setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper())
                     .setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper())
                     .setRecentTasks(mWMComponent.getRecentTasks())
-                    .setSizeCompatUI(Optional.of(mWMComponent.getSizeCompatUI()));
+                    .setSizeCompatUI(Optional.of(mWMComponent.getSizeCompatUI()))
+                    .setDragAndDrop(Optional.of(mWMComponent.getDragAndDrop()));
         } else {
             // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option
             // is separating this logic into newly creating SystemUITestsFactory.
@@ -140,7 +141,8 @@
                     .setStartingSurface(Optional.ofNullable(null))
                     .setTaskSurfaceHelper(Optional.ofNullable(null))
                     .setRecentTasks(Optional.ofNullable(null))
-                    .setSizeCompatUI(Optional.ofNullable(null));
+                    .setSizeCompatUI(Optional.ofNullable(null))
+                    .setDragAndDrop(Optional.ofNullable(null));
         }
         mSysUIComponent = builder.build();
         if (mInitializeComponents) {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
index 5fdf026..c5d3a70 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java
@@ -32,6 +32,7 @@
 import com.android.wm.shell.apppairs.AppPairs;
 import com.android.wm.shell.bubbles.Bubbles;
 import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
+import com.android.wm.shell.draganddrop.DragAndDrop;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.onehanded.OneHanded;
@@ -111,6 +112,9 @@
         @BindsInstance
         Builder setSizeCompatUI(Optional<SizeCompatUI> s);
 
+        @BindsInstance
+        Builder setDragAndDrop(Optional<DragAndDrop> d);
+
         SysUIComponent build();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
index 543ba8f..90a3ad2 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/WMComponent.java
@@ -29,6 +29,7 @@
 import com.android.wm.shell.dagger.WMShellModule;
 import com.android.wm.shell.dagger.WMSingleton;
 import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
+import com.android.wm.shell.draganddrop.DragAndDrop;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.onehanded.OneHanded;
@@ -119,4 +120,7 @@
 
     @WMSingleton
     SizeCompatUI getSizeCompatUI();
+
+    @WMSingleton
+    DragAndDrop getDragAndDrop();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index d27b5fc..aeef8cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -927,7 +927,9 @@
         int burnInYOffset = getBurnInOffset(mBurnInYOffset * 2, false /* xAxis */)
                 - mBurnInYOffset;
         mIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
-        mAmbientIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
+        if (mAmbientIndicationArea != null) {
+            mAmbientIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
+        }
     }
 
     public void setAntiBurnInOffsetX(int burnInXOffset) {
@@ -936,7 +938,9 @@
         }
         mBurnInXOffset = burnInXOffset;
         mIndicationArea.setTranslationX(burnInXOffset);
-        mAmbientIndicationArea.setTranslationX(burnInXOffset);
+        if (mAmbientIndicationArea != null) {
+            mAmbientIndicationArea.setTranslationX(burnInXOffset);
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index a56c177..b546edf 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -56,6 +56,7 @@
 import com.android.systemui.tracing.ProtoTracer;
 import com.android.systemui.tracing.nano.SystemUiTraceProto;
 import com.android.wm.shell.ShellCommandHandler;
+import com.android.wm.shell.draganddrop.DragAndDrop;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.nano.WmShellTraceProto;
@@ -114,6 +115,7 @@
     private final Optional<HideDisplayCutout> mHideDisplayCutoutOptional;
     private final Optional<ShellCommandHandler> mShellCommandHandler;
     private final Optional<SizeCompatUI> mSizeCompatUIOptional;
+    private final Optional<DragAndDrop> mDragAndDropOptional;
 
     private final CommandQueue mCommandQueue;
     private final ConfigurationController mConfigurationController;
@@ -142,6 +144,7 @@
             Optional<HideDisplayCutout> hideDisplayCutoutOptional,
             Optional<ShellCommandHandler> shellCommandHandler,
             Optional<SizeCompatUI> sizeCompatUIOptional,
+            Optional<DragAndDrop> dragAndDropOptional,
             CommandQueue commandQueue,
             ConfigurationController configurationController,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -167,6 +170,7 @@
         mProtoTracer = protoTracer;
         mShellCommandHandler = shellCommandHandler;
         mSizeCompatUIOptional = sizeCompatUIOptional;
+        mDragAndDropOptional = dragAndDropOptional;
         mSysUiMainExecutor = sysUiMainExecutor;
     }
 
@@ -182,6 +186,7 @@
         mOneHandedOptional.ifPresent(this::initOneHanded);
         mHideDisplayCutoutOptional.ifPresent(this::initHideDisplayCutout);
         mSizeCompatUIOptional.ifPresent(this::initSizeCompatUi);
+        mDragAndDropOptional.ifPresent(this::initDragAndDrop);
     }
 
     @VisibleForTesting
@@ -396,6 +401,20 @@
         mKeyguardUpdateMonitor.registerCallback(mSizeCompatUIKeyguardCallback);
     }
 
+    void initDragAndDrop(DragAndDrop dragAndDrop) {
+        mConfigurationController.addCallback(new ConfigurationController.ConfigurationListener() {
+            @Override
+            public void onConfigChanged(Configuration newConfig) {
+                dragAndDrop.onConfigChanged(newConfig);
+            }
+
+            @Override
+            public void onThemeChanged() {
+                dragAndDrop.onThemeChanged();
+            }
+        });
+    }
+
     @Override
     public void writeToProto(SystemUiTraceProto proto) {
         if (proto.wmShell == null) {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index de8cc89..ef9b850 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -1056,6 +1056,16 @@
         verify(callback, atLeastOnce()).onRequireUnlockForNfc();
     }
 
+    @Test
+    public void testFaceDoesNotAuth_afterPinAttempt() {
+        mTestableLooper.processAllMessages();
+        mKeyguardUpdateMonitor.setCredentialAttempted();
+        verify(mFingerprintManager, never()).authenticate(any(), any(), any(),
+                any(), anyInt());
+        verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+                anyBoolean());
+    }
+
     private void setKeyguardBouncerVisibility(boolean isVisible) {
         mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isVisible);
         mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
index ae7afce..1e15d2a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/WMShellTest.java
@@ -35,6 +35,7 @@
 import com.android.systemui.tracing.ProtoTracer;
 import com.android.wm.shell.ShellCommandHandler;
 import com.android.wm.shell.common.ShellExecutor;
+import com.android.wm.shell.draganddrop.DragAndDrop;
 import com.android.wm.shell.hidedisplaycutout.HideDisplayCutout;
 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
 import com.android.wm.shell.onehanded.OneHanded;
@@ -79,6 +80,7 @@
     @Mock ShellCommandHandler mShellCommandHandler;
     @Mock SizeCompatUI mSizeCompatUI;
     @Mock ShellExecutor mSysUiMainExecutor;
+    @Mock DragAndDrop mDragAndDrop;
 
     @Before
     public void setUp() {
@@ -87,6 +89,7 @@
         mWMShell = new WMShell(mContext, Optional.of(mPip), Optional.of(mLegacySplitScreen),
                 Optional.of(mSplitScreen), Optional.of(mOneHanded), Optional.of(mHideDisplayCutout),
                 Optional.of(mShellCommandHandler), Optional.of(mSizeCompatUI),
+                Optional.of(mDragAndDrop),
                 mCommandQueue, mConfigurationController, mKeyguardUpdateMonitor,
                 mNavigationModeController, mScreenLifecycle, mSysUiState, mProtoTracer,
                 mWakefulnessLifecycle, mSysUiMainExecutor);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index df2ae98..9a371f3 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -157,6 +157,7 @@
 import com.android.internal.app.procstats.ServiceState;
 import com.android.internal.messages.nano.SystemMessageProto;
 import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.os.SomeArgs;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.FastPrintWriter;
@@ -4209,9 +4210,12 @@
             if (r.app != null) {
                 Message msg = mAm.mHandler.obtainMessage(
                         ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
-                msg.obj = r.app;
-                msg.getData().putCharSequence(
-                    ActivityManagerService.SERVICE_RECORD_KEY, r.toString());
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = r.app;
+                args.arg2 = r.toString();
+                args.arg3 = r.getComponentName();
+
+                msg.obj = args;
                 mAm.mHandler.sendMessage(msg);
             }
         }
@@ -5272,11 +5276,14 @@
         }
     }
 
-    void serviceForegroundCrash(ProcessRecord app, CharSequence serviceRecord) {
-        mAm.crashApplicationWithType(app.uid, app.getPid(), app.info.packageName, app.userId,
+    void serviceForegroundCrash(ProcessRecord app, String serviceRecord,
+            ComponentName service) {
+        mAm.crashApplicationWithTypeWithExtras(
+                app.uid, app.getPid(), app.info.packageName, app.userId,
                 "Context.startForegroundService() did not then call Service.startForeground(): "
                     + serviceRecord, false /*force*/,
-                ForegroundServiceDidNotStartInTimeException.TYPE_ID);
+                ForegroundServiceDidNotStartInTimeException.TYPE_ID,
+                ForegroundServiceDidNotStartInTimeException.createExtrasForService(service));
     }
 
     void scheduleServiceTimeoutLocked(ProcessRecord proc) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index dde1ed9..53b1608 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -338,6 +338,7 @@
 import com.android.internal.os.ByteTransferPipe;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.os.ProcessCpuTracker;
+import com.android.internal.os.SomeArgs;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.os.Zygote;
 import com.android.internal.policy.AttributeCache;
@@ -1472,8 +1473,6 @@
 
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
 
-    static final String SERVICE_RECORD_KEY = "servicerecord";
-
     /**
      * Flag whether the current user is a "monkey", i.e. whether
      * the UI is driven by a UI automation tool.
@@ -1652,8 +1651,12 @@
                 mServices.serviceForegroundTimeout((ServiceRecord) msg.obj);
             } break;
             case SERVICE_FOREGROUND_CRASH_MSG: {
-                mServices.serviceForegroundCrash((ProcessRecord) msg.obj,
-                        msg.getData().getCharSequence(SERVICE_RECORD_KEY));
+                SomeArgs args = (SomeArgs) msg.obj;
+                mServices.serviceForegroundCrash(
+                        (ProcessRecord) args.arg1,
+                        (String) args.arg2,
+                        (ComponentName) args.arg3);
+                args.recycle();
             } break;
             case UPDATE_TIME_ZONE: {
                 synchronized (mProcLock) {
@@ -3001,6 +3004,14 @@
     @Override
     public void crashApplicationWithType(int uid, int initialPid, String packageName, int userId,
             String message, boolean force, int exceptionTypeId) {
+        crashApplicationWithTypeWithExtras(uid, initialPid, packageName, userId, message,
+                force, exceptionTypeId, null);
+    }
+
+    @Override
+    public void crashApplicationWithTypeWithExtras(int uid, int initialPid, String packageName,
+            int userId, String message, boolean force, int exceptionTypeId,
+            @Nullable Bundle extras) {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
                 != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: crashApplication() from pid="
@@ -3013,7 +3024,7 @@
 
         synchronized(this) {
             mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId,
-                    message, force, exceptionTypeId);
+                    message, force, exceptionTypeId, extras);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index bcb42bb..0bf0fe2 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -27,6 +27,7 @@
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
 
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.AnrController;
@@ -40,6 +41,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Message;
 import android.os.Process;
 import android.os.SystemClock;
@@ -489,7 +491,7 @@
      * @param message
      */
     void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId,
-            String message, boolean force, int exceptionTypeId) {
+            String message, boolean force, int exceptionTypeId, @Nullable Bundle extras) {
         ProcessRecord proc = null;
 
         // Figure out which process to kill.  We don't trust that initialPid
@@ -521,7 +523,7 @@
             return;
         }
 
-        proc.scheduleCrashLocked(message, exceptionTypeId);
+        proc.scheduleCrashLocked(message, exceptionTypeId, extras);
         if (force) {
             // If the app is responsive, the scheduled crash will happen as expected
             // and then the delayed summary kill will be a no-op.
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 487101b..2da4107 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -611,7 +611,7 @@
                         Slog.w(TAG, "Can't deliver broadcast to " + app.processName
                                 + " (pid " + app.getPid() + "). Crashing it.");
                         app.scheduleCrashLocked("can't deliver broadcast",
-                                CannotDeliverBroadcastException.TYPE_ID);
+                                CannotDeliverBroadcastException.TYPE_ID, /* extras=*/ null);
                     }
                     throw ex;
                 }
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 14ba716..b9d7917 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -31,6 +31,7 @@
 import android.content.pm.VersionedPackage;
 import android.content.res.CompatibilityInfo;
 import android.os.Binder;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Process;
 import android.os.RemoteException;
@@ -958,7 +959,7 @@
      *                        of its subclasses.
      */
     @GuardedBy("mService")
-    void scheduleCrashLocked(String message, int exceptionTypeId) {
+    void scheduleCrashLocked(String message, int exceptionTypeId, @Nullable Bundle extras) {
         // Checking killedbyAm should keep it from showing the crash dialog if the process
         // was already dead for a good / normal reason.
         if (!mKilledByAm) {
@@ -969,7 +970,7 @@
                 }
                 final long ident = Binder.clearCallingIdentity();
                 try {
-                    mThread.scheduleCrash(message, exceptionTypeId);
+                    mThread.scheduleCrash(message, exceptionTypeId, extras);
                 } catch (RemoteException e) {
                     // If it's already dead our work is done. If it's wedged just kill it.
                     // We won't get the crash dialog or the error reporting.
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index 792feea..806a5dd 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -31,7 +31,6 @@
 import android.content.Context;
 import android.hardware.devicestate.DeviceStateInfo;
 import android.hardware.devicestate.DeviceStateManager;
-import android.hardware.devicestate.DeviceStateManagerInternal;
 import android.hardware.devicestate.IDeviceStateManager;
 import android.hardware.devicestate.IDeviceStateManagerCallback;
 import android.os.Binder;
@@ -162,7 +161,6 @@
     @Override
     public void onStart() {
         publishBinderService(Context.DEVICE_STATE_SERVICE, mBinderService);
-        publishLocalService(DeviceStateManagerInternal.class, new LocalService());
     }
 
     @VisibleForTesting
@@ -242,6 +240,13 @@
     }
 
     /** Returns the list of currently supported device state identifiers. */
+    private int[] getSupportedStateIdentifiers() {
+        synchronized (mLock) {
+            return getSupportedStateIdentifiersLocked();
+        }
+    }
+
+    /** Returns the list of currently supported device state identifiers. */
     private int[] getSupportedStateIdentifiersLocked() {
         int[] supportedStates = new int[mDeviceStates.size()];
         for (int i = 0; i < supportedStates.length; i++) {
@@ -843,14 +848,4 @@
             }
         }
     }
-
-    /** Implementation of {@link DeviceStateManagerInternal} published as a local service. */
-    private final class LocalService extends DeviceStateManagerInternal {
-        @Override
-        public int[] getSupportedStateIdentifiers() {
-            synchronized (mLock) {
-                return getSupportedStateIdentifiersLocked();
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index fadaf10..539e0c0 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -53,7 +53,6 @@
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
 import android.hardware.devicestate.DeviceStateManager;
-import android.hardware.devicestate.DeviceStateManagerInternal;
 import android.hardware.display.AmbientBrightnessDayStats;
 import android.hardware.display.BrightnessChangeEvent;
 import android.hardware.display.BrightnessConfiguration;
@@ -132,7 +131,6 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
-import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
@@ -212,7 +210,6 @@
     private WindowManagerInternal mWindowManagerInternal;
     private InputManagerInternal mInputManagerInternal;
     private IMediaProjectionManager mProjectionService;
-    private DeviceStateManagerInternal mDeviceStateManager;
     private int[] mUserDisabledHdrTypes = {};
     private boolean mAreUserDisabledHdrTypesAllowed = true;
 
@@ -560,9 +557,10 @@
             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
             mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
 
-            mDeviceStateManager = LocalServices.getService(DeviceStateManagerInternal.class);
-            mContext.getSystemService(DeviceStateManager.class).registerCallback(
-                    new HandlerExecutor(mHandler), new DeviceStateListener());
+            DeviceStateManager deviceStateManager =
+                    mContext.getSystemService(DeviceStateManager.class);
+            deviceStateManager.registerCallback(new HandlerExecutor(mHandler),
+                    new DeviceStateListener());
 
             scheduleTraversalLocked(false);
         }
@@ -3292,53 +3290,6 @@
         }
 
         @Override
-        public Set<DisplayInfo> getPossibleDisplayInfo(int displayId) {
-            synchronized (mSyncRoot) {
-                // Retrieve the group associated with this display id.
-                final int displayGroupId =
-                        mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(displayId);
-                if (displayGroupId == Display.INVALID_DISPLAY_GROUP) {
-                    Slog.w(TAG,
-                            "Can't get possible display info since display group for " + displayId
-                                    + " does not exist");
-                    return new ArraySet<>();
-                }
-
-                // Assume any display in this group can be swapped out for the given display id.
-                Set<DisplayInfo> possibleInfo = new ArraySet<>();
-                final DisplayGroup group = mLogicalDisplayMapper.getDisplayGroupLocked(
-                        displayGroupId);
-                for (int i = 0; i < group.getSizeLocked(); i++) {
-                    final int id = group.getIdLocked(i);
-                    final LogicalDisplay logical = mLogicalDisplayMapper.getDisplayLocked(id);
-                    if (logical == null) {
-                        Slog.w(TAG,
-                                "Can't get possible display info since logical display for "
-                                        + "display id " + id + " does not exist, as part of group "
-                                        + displayGroupId);
-                    } else {
-                        possibleInfo.add(logical.getDisplayInfoLocked());
-                    }
-                }
-
-                // For the supported device states, retrieve the DisplayInfos for the logical
-                // display layout.
-                if (mDeviceStateManager == null) {
-                    Slog.w(TAG, "Can't get supported states since DeviceStateManager not ready");
-                } else {
-                    final int[] supportedStates =
-                            mDeviceStateManager.getSupportedStateIdentifiers();
-                    for (int state : supportedStates) {
-                        possibleInfo.addAll(
-                                mLogicalDisplayMapper.getDisplayInfoForStateLocked(state, displayId,
-                                        displayGroupId));
-                    }
-                }
-                return possibleInfo;
-            }
-        }
-
-        @Override
         public Point getDisplayPosition(int displayId) {
             synchronized (mSyncRoot) {
                 final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(displayId);
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index 0fbc3e8..f0093bd 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -26,7 +26,6 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.text.TextUtils;
-import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -41,7 +40,6 @@
 
 import java.io.PrintWriter;
 import java.util.Arrays;
-import java.util.Set;
 import java.util.function.Consumer;
 
 /**
@@ -267,61 +265,6 @@
         return mDisplayGroups.get(groupId);
     }
 
-    /**
-     * Returns the set of {@link DisplayInfo} for this device state, only fetching the info that is
-     * part of the same display group as the provided display id. The DisplayInfo represent the
-     * logical display layouts possible for the given device state.
-     *
-     * @param deviceState the state to query possible layouts for
-     * @param displayId   the display id to apply to all displays within the group
-     * @param groupId     the display group to filter display info for. Must be the same group as
-     *                    the display with the provided display id.
-     */
-    public Set<DisplayInfo> getDisplayInfoForStateLocked(int deviceState, int displayId,
-            int groupId) {
-        Set<DisplayInfo> displayInfos = new ArraySet<>();
-        final Layout layout = mDeviceStateToLayoutMap.get(deviceState);
-        final int layoutSize = layout.size();
-        for (int i = 0; i < layoutSize; i++) {
-            Layout.Display displayLayout = layout.getAt(i);
-            if (displayLayout == null) {
-                continue;
-            }
-
-            // If the underlying display-device we want to use for this display
-            // doesn't exist, then skip it. This can happen at startup as display-devices
-            // trickle in one at a time. When the new display finally shows up, the layout is
-            // recalculated so that the display is properly added to the current layout.
-            final DisplayAddress address = displayLayout.getAddress();
-            final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address);
-            if (device == null) {
-                Slog.w(TAG, "The display device (" + address + "), is not available"
-                        + " for the display state " + deviceState);
-                continue;
-            }
-
-            // Find or create the LogicalDisplay to map the DisplayDevice to.
-            final int logicalDisplayId = displayLayout.getLogicalDisplayId();
-            final LogicalDisplay logicalDisplay = getDisplayLocked(logicalDisplayId);
-            if (logicalDisplay == null) {
-                Slog.w(TAG, "The logical display (" + address + "), is not available"
-                        + " for the display state " + deviceState);
-                continue;
-            }
-            final DisplayInfo temp = logicalDisplay.getDisplayInfoLocked();
-            DisplayInfo displayInfo = new DisplayInfo(temp);
-            if (displayInfo.displayGroupId != groupId) {
-                // Ignore any displays not in the provided group.
-                continue;
-            }
-            // A display in the same group can be swapped out at any point, so set the display id
-            // for all results to the provided display id.
-            displayInfo.displayId = displayId;
-            displayInfos.add(displayInfo);
-        }
-        return displayInfos;
-    }
-
     public void dumpLocked(PrintWriter pw) {
         pw.println("LogicalDisplayMapper:");
         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
diff --git a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java b/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
deleted file mode 100644
index ef8dee4..0000000
--- a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_270;
-
-import android.hardware.display.DisplayManagerInternal;
-import android.util.ArraySet;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.view.DisplayInfo;
-import android.view.Surface;
-
-import java.util.Set;
-
-/**
- * Maintains a map of possible {@link DisplayInfo} for displays and states that may be encountered
- * on a device. This is not guaranteed to include all possible device states for all displays.
- *
- * By 'possible', this class only handles device states for displays and display groups it is
- * currently aware of. It can not handle all eventual states the system may enter, for example, if
- * an external display is added, or a new display is added to the group.
- */
-public class PossibleDisplayInfoMapper {
-    private static final String TAG = "PossibleDisplayInfoMapper";
-    private static final boolean DEBUG = false;
-
-    private final DisplayManagerInternal mDisplayManagerInternal;
-
-    /**
-     * Map of all logical displays, indexed by logical display id.
-     * Each logical display has multiple entries, one for each possible rotation and device
-     * state.
-     *
-     * Emptied and re-calculated when a display is added, removed, or changed.
-     */
-    private final SparseArray<Set<DisplayInfo>> mDisplayInfos = new SparseArray<>();
-
-    PossibleDisplayInfoMapper(DisplayManagerInternal displayManagerInternal) {
-        mDisplayManagerInternal = displayManagerInternal;
-    }
-
-
-    /**
-     * Returns, for the given displayId, a set of display infos. Set contains the possible rotations
-     * for each supported device state.
-     */
-    public Set<DisplayInfo> getPossibleDisplayInfos(int displayId) {
-        // Update display infos before returning, since any cached values would have been removed
-        // in response to any display event. This model avoids re-computing the cache for every
-        // display change event (which occurs extremely frequently in the normal usage of the
-        // device).
-        updatePossibleDisplayInfos(displayId);
-        if (!mDisplayInfos.contains(displayId)) {
-            return new ArraySet<>();
-        }
-        return Set.copyOf(mDisplayInfos.get(displayId));
-    }
-
-    /**
-     * Updates the possible {@link DisplayInfo}s for the given display, by calculating the
-     * DisplayInfo for each rotation across supported device states.
-     */
-    public void updatePossibleDisplayInfos(int displayId) {
-        Set<DisplayInfo> displayInfos = mDisplayManagerInternal.getPossibleDisplayInfo(displayId);
-        if (DEBUG) {
-            Slog.v(TAG, "updatePossibleDisplayInfos, calculate rotations for given DisplayInfo "
-                    + displayInfos.size() + " on display " + displayId);
-        }
-        updateDisplayInfos(displayInfos);
-    }
-
-    /**
-     * For the given displayId, removes all possible {@link DisplayInfo}.
-     */
-    public void removePossibleDisplayInfos(int displayId) {
-        if (DEBUG && mDisplayInfos.get(displayId) != null) {
-            Slog.v(TAG, "onDisplayRemoved, remove all DisplayInfo (" + mDisplayInfos.get(
-                    displayId).size() + ") with id " + displayId);
-        }
-        mDisplayInfos.remove(displayId);
-    }
-
-    private void updateDisplayInfos(Set<DisplayInfo> displayInfos) {
-        // Empty out cache before re-computing.
-        mDisplayInfos.clear();
-        DisplayInfo[] originalDisplayInfos = new DisplayInfo[displayInfos.size()];
-        displayInfos.toArray(originalDisplayInfos);
-        // Iterate over each logical display layout for the current state.
-        Set<DisplayInfo> rotatedDisplayInfos;
-        for (DisplayInfo di : originalDisplayInfos) {
-            rotatedDisplayInfos = new ArraySet<>();
-            // Calculate all possible rotations for each logical display.
-            for (int rotation = ROTATION_0; rotation <= ROTATION_270; rotation++) {
-                rotatedDisplayInfos.add(applyRotation(di, rotation));
-            }
-            // Combine all results under the logical display id.
-            Set<DisplayInfo> priorDisplayInfos = mDisplayInfos.get(di.displayId, new ArraySet<>());
-            priorDisplayInfos.addAll(rotatedDisplayInfos);
-            mDisplayInfos.put(di.displayId, priorDisplayInfos);
-        }
-    }
-
-    private static DisplayInfo applyRotation(DisplayInfo displayInfo,
-            @Surface.Rotation int rotation) {
-        DisplayInfo updatedDisplayInfo = new DisplayInfo();
-        updatedDisplayInfo.copyFrom(displayInfo);
-        updatedDisplayInfo.rotation = rotation;
-
-        final int naturalWidth = updatedDisplayInfo.getNaturalWidth();
-        final int naturalHeight = updatedDisplayInfo.getNaturalHeight();
-        updatedDisplayInfo.logicalWidth = naturalWidth;
-        updatedDisplayInfo.logicalHeight = naturalHeight;
-        return updatedDisplayInfo;
-    }
-}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 3ffa62d..fbc8f73 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2587,9 +2587,6 @@
             if (mService.isBooted() || mService.isBooting()) {
                 startSystemDecorations(display);
             }
-            // Drop any cached DisplayInfos associated with this display id - the values are now
-            // out of date given this display added event.
-            mWmService.mPossibleDisplayInfoMapper.removePossibleDisplayInfos(displayId);
         }
     }
 
@@ -2610,8 +2607,8 @@
             if (displayContent == null) {
                 return;
             }
+
             displayContent.remove();
-            mWmService.mPossibleDisplayInfoMapper.removePossibleDisplayInfos(displayId);
         }
     }
 
@@ -2623,9 +2620,6 @@
             if (displayContent != null) {
                 displayContent.onDisplayChanged();
             }
-            // Drop any cached DisplayInfos associated with this display id - the values are now
-            // out of date given this display changed event.
-            mWmService.mPossibleDisplayInfoMapper.removePossibleDisplayInfos(displayId);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cc7485c..a8697a5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -47,6 +47,8 @@
 import static android.provider.Settings.Global.DEVELOPMENT_WM_DISPLAY_SETTINGS_PATH;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
 import static android.view.WindowManager.DISPLAY_IME_POLICY_FALLBACK_DISPLAY;
 import static android.view.WindowManager.DISPLAY_IME_POLICY_LOCAL;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
@@ -330,11 +332,13 @@
 import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.Set;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
@@ -1063,10 +1067,6 @@
 
     final HighRefreshRateDenylist mHighRefreshRateDenylist;
 
-    // Maintainer of a collection of all possible DisplayInfo for all configurations of the
-    // logical displays.
-    final PossibleDisplayInfoMapper mPossibleDisplayInfoMapper;
-
     // If true, only the core apps and services are being launched because the device
     // is in a special boot mode, such as being encrypted or waiting for a decryption password.
     // For example, when this flag is true, there will be no wallpaper service.
@@ -1242,7 +1242,6 @@
 
         mInputManager = inputManager; // Must be before createDisplayContentLocked.
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
-        mPossibleDisplayInfoMapper = new PossibleDisplayInfoMapper(mDisplayManagerInternal);
 
         mSurfaceControlFactory = surfaceControlFactory;
         mTransactionFactory = transactionFactory;
@@ -8583,10 +8582,23 @@
                             + " for getPossibleMaximumWindowMetrics");
                     return new ArrayList<>();
                 }
+                // TODO(181127261) DisplayInfo should be pushed from DisplayManager.
+                final DisplayContent dc = mRoot.getDisplayContent(displayId);
+                if (dc == null) {
+                    Slog.e(TAG, "Invalid displayId " + displayId
+                            + " for getPossibleMaximumWindowMetrics");
+                    return new ArrayList<>();
+                }
 
-                // Retrieve the DisplayInfo for all possible rotations across all possible display
-                // layouts.
-                return List.copyOf(mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId));
+                // TODO(181127261) DisplayManager should provide a DisplayInfo for each rotation
+                DisplayInfo currentDisplayInfo = dc.getDisplayInfo();
+                Set<DisplayInfo> displayInfoSet = new HashSet<>();
+                for (int rotation = ROTATION_0; rotation <= ROTATION_270; rotation++) {
+                    currentDisplayInfo.rotation = rotation;
+                    // TODO(181127261) Retrieve the device state from display stack.
+                    displayInfoSet.add(new DisplayInfo(currentDisplayInfo));
+                }
+                return new ArrayList<DisplayInfo>(displayInfoSet);
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
diff --git a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
index 03eba9b..ee0723b 100644
--- a/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicestate/DeviceStateManagerServiceTest.java
@@ -18,8 +18,6 @@
 
 import static android.hardware.devicestate.DeviceStateManager.INVALID_DEVICE_STATE;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 import static org.testng.Assert.assertEquals;
@@ -183,10 +181,8 @@
         assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
         assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE,
-                OTHER_DEVICE_STATE);
 
-        mProvider.notifySupportedDeviceStates(new DeviceState[]{DEFAULT_DEVICE_STATE});
+        mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE });
         flushHandler();
 
         // The current committed and requests states do not change because the current state remains
@@ -194,10 +190,9 @@
         assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
         assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE);
 
         assertArrayEquals(callback.getLastNotifiedInfo().supportedStates,
-                new int[]{DEFAULT_DEVICE_STATE.getIdentifier()});
+                new int[] { DEFAULT_DEVICE_STATE.getIdentifier() });
     }
 
     @Test
@@ -212,11 +207,9 @@
         assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
         assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE,
-                OTHER_DEVICE_STATE);
 
-        mProvider.notifySupportedDeviceStates(new DeviceState[]{DEFAULT_DEVICE_STATE,
-                OTHER_DEVICE_STATE});
+        mProvider.notifySupportedDeviceStates(new DeviceState[]{ DEFAULT_DEVICE_STATE,
+                OTHER_DEVICE_STATE });
         flushHandler();
 
         // The current committed and requests states do not change because the current state remains
@@ -224,8 +217,6 @@
         assertEquals(mService.getCommittedState(), Optional.of(DEFAULT_DEVICE_STATE));
         assertEquals(mService.getPendingState(), Optional.empty());
         assertEquals(mService.getBaseState(), Optional.of(DEFAULT_DEVICE_STATE));
-        assertThat(mService.getSupportedStates()).asList().containsExactly(DEFAULT_DEVICE_STATE,
-                OTHER_DEVICE_STATE);
 
         // The callback wasn't notified about a change in supported states as the states have not
         // changed.
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index fbc1952..8279624 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -16,17 +16,12 @@
 
 package com.android.server.display;
 
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.DEFAULT_DISPLAY_GROUP;
-
 import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED;
 import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED;
 import static com.android.server.display.DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED;
 import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_ADDED;
 import static com.android.server.display.LogicalDisplayMapper.LOGICAL_DISPLAY_EVENT_REMOVED;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.mockito.ArgumentMatchers.eq;
@@ -60,7 +55,6 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.Arrays;
-import java.util.Set;
 
 @SmallTest
 @Presubmit
@@ -129,14 +123,14 @@
         // add
         LogicalDisplay displayAdded = add(device);
         assertEquals(info(displayAdded).address, info(device).address);
-        assertEquals(DEFAULT_DISPLAY, id(displayAdded));
+        assertEquals(Display.DEFAULT_DISPLAY, id(displayAdded));
 
         // remove
         mDisplayDeviceRepo.onDisplayDeviceEvent(device, DISPLAY_DEVICE_EVENT_REMOVED);
         verify(mListenerMock).onLogicalDisplayEventLocked(
                 mDisplayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_REMOVED));
         LogicalDisplay displayRemoved = mDisplayCaptor.getValue();
-        assertEquals(DEFAULT_DISPLAY, id(displayRemoved));
+        assertEquals(Display.DEFAULT_DISPLAY, id(displayRemoved));
         assertEquals(displayAdded, displayRemoved);
     }
 
@@ -161,11 +155,11 @@
 
         LogicalDisplay display1 = add(device1);
         assertEquals(info(display1).address, info(device1).address);
-        assertNotEquals(DEFAULT_DISPLAY, id(display1));
+        assertNotEquals(Display.DEFAULT_DISPLAY, id(display1));
 
         LogicalDisplay display2 = add(device2);
         assertEquals(info(display2).address, info(device2).address);
-        assertEquals(DEFAULT_DISPLAY, id(display2));
+        assertEquals(Display.DEFAULT_DISPLAY, id(display2));
     }
 
     @Test
@@ -177,12 +171,12 @@
 
         LogicalDisplay display1 = add(device1);
         assertEquals(info(display1).address, info(device1).address);
-        assertEquals(DEFAULT_DISPLAY, id(display1));
+        assertEquals(Display.DEFAULT_DISPLAY, id(display1));
 
         LogicalDisplay display2 = add(device2);
         assertEquals(info(display2).address, info(device2).address);
         // Despite the flags, we can only have one default display
-        assertNotEquals(DEFAULT_DISPLAY, id(display2));
+        assertNotEquals(Display.DEFAULT_DISPLAY, id(display2));
     }
 
     @Test
@@ -195,67 +189,7 @@
         int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID);
         assertEquals(3, ids.length);
         Arrays.sort(ids);
-        assertEquals(DEFAULT_DISPLAY, ids[0]);
-    }
-
-    @Test
-    public void testGetDisplayInfoForStateLocked_oneDisplayGroup_internalType() {
-        add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
-        add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
-        add(createDisplayDevice(Display.TYPE_INTERNAL, 700, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
-
-        Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked(
-                DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP);
-        assertThat(displayInfos.size()).isEqualTo(3);
-        for (DisplayInfo displayInfo : displayInfos) {
-            assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY);
-            assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP);
-            assertThat(displayInfo.logicalWidth).isAnyOf(600, 200, 700);
-            assertThat(displayInfo.logicalHeight).isEqualTo(800);
-        }
-    }
-
-    @Test
-    public void testGetDisplayInfoForStateLocked_oneDisplayGroup_differentTypes() {
-        add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
-        add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
-        add(createDisplayDevice(Display.TYPE_EXTERNAL, 700, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
-
-        Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked(
-                DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP);
-        assertThat(displayInfos.size()).isEqualTo(2);
-        for (DisplayInfo displayInfo : displayInfos) {
-            assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY);
-            assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP);
-            assertThat(displayInfo.logicalWidth).isAnyOf(600, 200);
-            assertThat(displayInfo.logicalHeight).isEqualTo(800);
-        }
-    }
-
-    @Test
-    public void testGetDisplayInfoForStateLocked_multipleDisplayGroups_defaultGroup() {
-        add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
-        add(createDisplayDevice(Display.TYPE_INTERNAL, 200, 800,
-                DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY));
-        add(createDisplayDevice(Display.TYPE_VIRTUAL, 700, 800,
-                DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP));
-
-        Set<DisplayInfo> displayInfos = mLogicalDisplayMapper.getDisplayInfoForStateLocked(
-                DeviceStateToLayoutMap.STATE_DEFAULT, DEFAULT_DISPLAY, DEFAULT_DISPLAY_GROUP);
-        assertThat(displayInfos.size()).isEqualTo(2);
-        for (DisplayInfo displayInfo : displayInfos) {
-            assertThat(displayInfo.displayId).isEqualTo(DEFAULT_DISPLAY);
-            assertThat(displayInfo.displayGroupId).isEqualTo(DEFAULT_DISPLAY_GROUP);
-            assertThat(displayInfo.logicalWidth).isAnyOf(600, 200);
-            assertThat(displayInfo.logicalHeight).isEqualTo(800);
-        }
+        assertEquals(Display.DEFAULT_DISPLAY, ids[0]);
     }
 
     @Test
@@ -265,11 +199,11 @@
         LogicalDisplay display2 = add(createDisplayDevice(Display.TYPE_INTERNAL, 600, 800, 0));
         LogicalDisplay display3 = add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0));
 
-        assertEquals(DEFAULT_DISPLAY_GROUP,
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
                 mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display1)));
-        assertEquals(DEFAULT_DISPLAY_GROUP,
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
                 mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display2)));
-        assertEquals(DEFAULT_DISPLAY_GROUP,
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
                 mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3)));
     }
 
@@ -284,11 +218,11 @@
                 DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
         LogicalDisplay display3 = add(device3);
 
-        assertEquals(DEFAULT_DISPLAY_GROUP,
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
                 mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display1)));
-        assertEquals(DEFAULT_DISPLAY_GROUP,
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
                 mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display2)));
-        assertNotEquals(DEFAULT_DISPLAY_GROUP,
+        assertNotEquals(Display.DEFAULT_DISPLAY_GROUP,
                 mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3)));
 
         // Now switch it back to the default group by removing the flag and issuing an update
@@ -297,7 +231,7 @@
         mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
 
         // Verify the new group is correct.
-        assertEquals(DEFAULT_DISPLAY_GROUP,
+        assertEquals(Display.DEFAULT_DISPLAY_GROUP,
                 mLogicalDisplayMapper.getDisplayGroupIdFromDisplayIdLocked(id(display3)));
     }
 
@@ -353,14 +287,14 @@
         // add
         LogicalDisplay displayAdded = add(device);
         assertEquals(info(displayAdded).address, info(device).address);
-        assertNotEquals(DEFAULT_DISPLAY, id(displayAdded));
+        assertNotEquals(Display.DEFAULT_DISPLAY, id(displayAdded));
 
         // remove
         mDisplayDeviceRepo.onDisplayDeviceEvent(device, DISPLAY_DEVICE_EVENT_REMOVED);
         verify(mListenerMock).onLogicalDisplayEventLocked(
                 mDisplayCaptor.capture(), eq(LOGICAL_DISPLAY_EVENT_REMOVED));
         LogicalDisplay displayRemoved = mDisplayCaptor.getValue();
-        assertNotEquals(DEFAULT_DISPLAY, id(displayRemoved));
+        assertNotEquals(Display.DEFAULT_DISPLAY, id(displayRemoved));
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java b/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java
deleted file mode 100644
index 6e00568..0000000
--- a/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.wm;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.Display.FLAG_PRESENTATION;
-import static android.view.Surface.ROTATION_0;
-import static android.view.Surface.ROTATION_180;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
-
-import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
-import android.util.ArraySet;
-import android.view.DisplayInfo;
-
-import androidx.test.filters.MediumTest;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Set;
-
-
-/**
- * Tests for {@link PossibleDisplayInfoMapper}.
- *
- * Build/Install/Run:
- * atest WmTests:PossibleDisplayInfoMapperTests
- */
-@MediumTest
-@Presubmit
-@RunWith(WindowTestRunner.class)
-public class PossibleDisplayInfoMapperTests extends WindowTestsBase {
-
-    private PossibleDisplayInfoMapper mDisplayInfoMapper;
-    private final Set<DisplayInfo> mPossibleDisplayInfo = new ArraySet<>();
-    private DisplayInfo mDefaultDisplayInfo;
-    private DisplayInfo mSecondDisplayInfo;
-
-    @Before
-    public void setUp() throws Exception {
-        mDisplayInfoMapper = mWm.mPossibleDisplayInfoMapper;
-        final DisplayInfo baseDisplayInfo = mWm.mRoot.getDisplayContent(
-                DEFAULT_DISPLAY).getDisplayInfo();
-        when(mWm.mDisplayManagerInternal.getPossibleDisplayInfo(anyInt())).thenReturn(
-                mPossibleDisplayInfo);
-
-        mDefaultDisplayInfo = new DisplayInfo(baseDisplayInfo);
-        initializeDisplayInfo(mDefaultDisplayInfo, DEFAULT_DISPLAY, new Rect(0, 0, 500, 800));
-        mSecondDisplayInfo = new DisplayInfo(baseDisplayInfo);
-        // Use the same display id for any display in the same group, due to the assumption that
-        // any display in the same grouped can be swapped out for each other (while maintaining the
-        // display id).
-        initializeDisplayInfo(mSecondDisplayInfo, DEFAULT_DISPLAY, new Rect(0, 0, 600, 1600));
-        mSecondDisplayInfo.flags |= FLAG_PRESENTATION;
-    }
-
-    @Test
-    public void testInitialization_isEmpty() {
-        // Empty after initializing.
-        assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY)).isEmpty();
-
-        // Still empty after updating.
-        mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
-        assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY)).isEmpty();
-    }
-
-    @Test
-    public void testUpdatePossibleDisplayInfos_singleDisplay() {
-        mPossibleDisplayInfo.add(mDefaultDisplayInfo);
-        mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
-
-        Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY);
-        // An entry for each possible rotation, for a display that can be in a single state.
-        assertThat(displayInfos.size()).isEqualTo(4);
-        assertPossibleDisplayInfoEntries(displayInfos, mDefaultDisplayInfo);
-    }
-
-    @Test
-    public void testUpdatePossibleDisplayInfos_secondDisplayAdded_sameGroup() {
-        mPossibleDisplayInfo.add(mDefaultDisplayInfo);
-        mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
-
-        assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY).size()).isEqualTo(4);
-
-        // Add another display layout to the set of supported states.
-        mPossibleDisplayInfo.add(mSecondDisplayInfo);
-        mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
-
-        Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY);
-        Set<DisplayInfo> defaultDisplayInfos = new ArraySet<>();
-        Set<DisplayInfo> secondDisplayInfos = new ArraySet<>();
-        for (DisplayInfo di : displayInfos) {
-            if ((di.flags & FLAG_PRESENTATION) != 0) {
-                secondDisplayInfos.add(di);
-            } else {
-                defaultDisplayInfos.add(di);
-            }
-        }
-        // An entry for each possible rotation, for the default display.
-        assertThat(defaultDisplayInfos).hasSize(4);
-        assertPossibleDisplayInfoEntries(defaultDisplayInfos, mDefaultDisplayInfo);
-
-        // An entry for each possible rotation, for the second display.
-        assertThat(secondDisplayInfos).hasSize(4);
-        assertPossibleDisplayInfoEntries(secondDisplayInfos, mSecondDisplayInfo);
-    }
-
-    @Test
-    public void testUpdatePossibleDisplayInfos_secondDisplayAdded_differentGroup() {
-        mPossibleDisplayInfo.add(mDefaultDisplayInfo);
-        mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY);
-
-        assertThat(mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY).size()).isEqualTo(4);
-
-        // Add another display to a different group.
-        mSecondDisplayInfo.displayId = DEFAULT_DISPLAY + 1;
-        mSecondDisplayInfo.displayGroupId = mDefaultDisplayInfo.displayGroupId + 1;
-        mPossibleDisplayInfo.add(mSecondDisplayInfo);
-        mDisplayInfoMapper.updatePossibleDisplayInfos(mSecondDisplayInfo.displayId);
-
-        Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY);
-        // An entry for each possible rotation, for the default display.
-        assertThat(displayInfos).hasSize(4);
-        assertPossibleDisplayInfoEntries(displayInfos, mDefaultDisplayInfo);
-
-        Set<DisplayInfo> secondStateEntries =
-                mDisplayInfoMapper.getPossibleDisplayInfos(mSecondDisplayInfo.displayId);
-        // An entry for each possible rotation, for the second display.
-        assertThat(secondStateEntries).hasSize(4);
-        assertPossibleDisplayInfoEntries(secondStateEntries, mSecondDisplayInfo);
-    }
-
-    private static void initializeDisplayInfo(DisplayInfo outDisplayInfo, int displayId,
-            Rect logicalBounds) {
-        outDisplayInfo.displayId = displayId;
-        outDisplayInfo.rotation = ROTATION_0;
-        outDisplayInfo.logicalWidth = logicalBounds.width();
-        outDisplayInfo.logicalHeight = logicalBounds.height();
-    }
-
-    private static void assertPossibleDisplayInfoEntries(Set<DisplayInfo> displayInfos,
-            DisplayInfo expectedDisplayInfo) {
-        boolean[] seenEveryRotation = new boolean[4];
-        for (DisplayInfo displayInfo : displayInfos) {
-            final int rotation = displayInfo.rotation;
-            seenEveryRotation[rotation] = true;
-            assertThat(displayInfo.displayId).isEqualTo(expectedDisplayInfo.displayId);
-            assertEqualsRotatedDisplayInfo(displayInfo, expectedDisplayInfo);
-        }
-        assertThat(seenEveryRotation).isEqualTo(new boolean[]{true, true, true, true});
-    }
-
-    private static void assertEqualsRotatedDisplayInfo(DisplayInfo actual, DisplayInfo expected) {
-        if (actual.rotation == ROTATION_0 || actual.rotation == ROTATION_180) {
-            assertThat(actual.logicalWidth).isEqualTo(expected.logicalWidth);
-            assertThat(actual.logicalHeight).isEqualTo(expected.logicalHeight);
-        } else {
-            assertThat(actual.logicalWidth).isEqualTo(expected.logicalHeight);
-            assertThat(actual.logicalHeight).isEqualTo(expected.logicalWidth);
-        }
-    }
-}