Merge "WindowlessWindowManager floating window support"
diff --git a/core/java/android/view/WindowlessWindowLayout.java b/core/java/android/view/WindowlessWindowLayout.java
index 8ef4d78..6fb01f2 100644
--- a/core/java/android/view/WindowlessWindowLayout.java
+++ b/core/java/android/view/WindowlessWindowLayout.java
@@ -16,13 +16,19 @@
 
 package android.view;
 
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
+
 import android.app.WindowConfiguration.WindowingMode;
 import android.graphics.Rect;
 import android.view.WindowInsets.Type.InsetsType;
 import android.window.ClientWindowFrames;
 
+// TODO(b/262891212) use the real WindowLayout and remove WindowlessWindowLayout
+
 /**
  * Computes window frames for the windowless window.
+ *
  * @hide
  */
 public class WindowlessWindowLayout extends WindowLayout {
@@ -32,9 +38,32 @@
             Rect displayCutoutSafe, Rect windowBounds, @WindowingMode int windowingMode,
             int requestedWidth, int requestedHeight, @InsetsType int requestedVisibleTypes,
             float compatScale, ClientWindowFrames frames) {
-        frames.frame.set(0, 0, attrs.width, attrs.height);
+        if (frames.attachedFrame == null) {
+            frames.frame.set(0, 0, attrs.width, attrs.height);
+            frames.parentFrame.set(frames.frame);
+            frames.displayFrame.set(frames.frame);
+            return;
+        }
+
+        final int height = calculateLength(attrs.height, requestedHeight,
+                frames.attachedFrame.height());
+        final int width = calculateLength(attrs.width, requestedWidth,
+                frames.attachedFrame.width());
+        Gravity.apply(attrs.gravity, width, height, frames.attachedFrame,
+                (int) (attrs.x + attrs.horizontalMargin),
+                (int) (attrs.y + attrs.verticalMargin),
+                frames.frame);
         frames.displayFrame.set(frames.frame);
-        frames.parentFrame.set(frames.frame);
+        frames.parentFrame.set(frames.attachedFrame);
+    }
+
+    private static int calculateLength(int attrLength, int requestedLength, int parentLength) {
+        if (attrLength == MATCH_PARENT) {
+            return parentLength;
+        }
+        if (attrLength == WRAP_CONTENT) {
+            return requestedLength;
+        }
+        return attrLength;
     }
 }
-
diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java
index ecb5557..021193e 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -17,6 +17,7 @@
 package android.view;
 
 import android.annotation.Nullable;
+import android.app.WindowConfiguration;
 import android.content.res.Configuration;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -53,13 +54,21 @@
         IBinder mInputChannelToken;
         Region mInputRegion;
         IWindow mClient;
-        State(SurfaceControl sc, WindowManager.LayoutParams p, int displayId,
-              IBinder inputChannelToken, IWindow client) {
+        SurfaceControl mLeash;
+        Rect mFrame;
+        Rect mAttachedFrame;
+
+        State(SurfaceControl sc, WindowManager.LayoutParams p,
+                int displayId, IBinder inputChannelToken, IWindow client, SurfaceControl leash,
+                Rect frame, Rect attachedFrame) {
             mSurfaceControl = sc;
             mParams.copyFrom(p);
             mDisplayId = displayId;
             mInputChannelToken = inputChannelToken;
             mClient = client;
+            mLeash = leash;
+            mFrame = frame;
+            mAttachedFrame = attachedFrame;
         }
     };
 
@@ -85,6 +94,7 @@
     private InsetsState mInsetsState;
     private final ClientWindowFrames mTmpFrames = new ClientWindowFrames();
     private final MergedConfiguration mTmpConfig = new MergedConfiguration();
+    private final WindowlessWindowLayout mLayout = new WindowlessWindowLayout();
 
     public WindowlessWindowManager(Configuration c, SurfaceControl rootSurface,
             IBinder hostInputToken) {
@@ -137,8 +147,15 @@
         }
     }
 
-    protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
-        b.setParent(mRootSurface);
+    protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
+        // If this is the first window, the state map is empty and the parent surface is the
+        // root. Otherwise, the parent surface is in the state map.
+        synchronized (this) {
+            if (mStateForWindow.isEmpty()) {
+                return mRootSurface;
+            }
+            return mStateForWindow.get(attrs.token).mLeash;
+        }
     }
 
     /**
@@ -150,13 +167,20 @@
             InputChannel outInputChannel, InsetsState outInsetsState,
             InsetsSourceControl.Array outActiveControls, Rect outAttachedFrame,
             float[] outSizeCompatScale) {
-        final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession)
+        final SurfaceControl leash = new SurfaceControl.Builder(mSurfaceSession)
+                .setName(attrs.getTitle().toString() + "Leash")
+                .setCallsite("WindowlessWindowManager.addToDisplay")
+                .setParent(getParentSurface(window, attrs))
+                .build();
+
+        final SurfaceControl sc = new SurfaceControl.Builder(mSurfaceSession)
                 .setFormat(attrs.format)
                 .setBLASTLayer()
                 .setName(attrs.getTitle().toString())
-                .setCallsite("WindowlessWindowManager.addToDisplay");
-        attachToParentSurface(window, b);
-        final SurfaceControl sc = b.build();
+                .setCallsite("WindowlessWindowManager.addToDisplay")
+                .setHidden(false)
+                .setParent(leash)
+                .build();
 
         if (((attrs.inputFeatures &
                 WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0)) {
@@ -178,11 +202,22 @@
         }
 
         final State state = new State(sc, attrs, displayId,
-            outInputChannel != null ? outInputChannel.getToken() : null, window);
+                outInputChannel != null ? outInputChannel.getToken() : null, window,
+                leash, /* frame= */ new Rect(), /* attachedFrame= */ null);
+        Rect parentFrame = null;
         synchronized (this) {
+            State parentState = mStateForWindow.get(attrs.token);
+            if (parentState != null) {
+                parentFrame = parentState.mFrame;
+            }
             mStateForWindow.put(window.asBinder(), state);
         }
-        outAttachedFrame.set(0, 0, -1, -1);
+        state.mAttachedFrame = parentFrame;
+        if (parentFrame == null) {
+            outAttachedFrame.set(0, 0, -1, -1);
+        } else {
+            outAttachedFrame.set(parentFrame);
+        }
         outSizeCompatScale[0] = 1f;
 
         final int res = WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE |
@@ -227,6 +262,7 @@
                     "Invalid window token (never added or removed already)");
         }
         removeSurface(state.mSurfaceControl);
+        removeSurface(state.mLeash);
     }
 
     /** Separate from {@link #remove} so that subclasses can put removal on a sync transaction. */
@@ -301,6 +337,7 @@
                     "Invalid window token (never added or removed already)");
         }
         SurfaceControl sc = state.mSurfaceControl;
+        SurfaceControl leash = state.mLeash;
         SurfaceControl.Transaction t = new SurfaceControl.Transaction();
 
         int attrChanges = 0;
@@ -309,21 +346,37 @@
         }
         WindowManager.LayoutParams attrs = state.mParams;
 
+        ClientWindowFrames frames = new ClientWindowFrames();
+        frames.attachedFrame = state.mAttachedFrame;
+
+        mLayout.computeFrames(attrs, null, null, null, WindowConfiguration.WINDOWING_MODE_UNDEFINED,
+                requestedWidth, requestedHeight, 0, 0,
+                frames);
+
+        state.mFrame.set(frames.frame);
+        if (outFrames != null) {
+            outFrames.frame.set(frames.frame);
+            outFrames.parentFrame.set(frames.parentFrame);
+            outFrames.displayFrame.set(frames.displayFrame);
+        }
+
+        t.setPosition(leash, frames.frame.left, frames.frame.top);
+        t.setWindowCrop(leash, frames.frame.width(), frames.frame.height());
+
         if (viewFlags == View.VISIBLE) {
-            t.setOpaque(sc, isOpaque(attrs)).show(sc).apply();
+            // TODO(b/262892794) ViewRootImpl modifies the app's rendering SurfaceControl
+            // opaqueness. We shouldn't need to modify opaqueness for this SurfaceControl here or
+            // in the real WindowManager.
+            t.setOpaque(sc, isOpaque(attrs)).show(leash).apply();
             if (outSurfaceControl != null) {
                 outSurfaceControl.copyFrom(sc, "WindowlessWindowManager.relayout");
             }
         } else {
-            t.hide(sc).apply();
+            t.hide(leash).apply();
             if (outSurfaceControl != null) {
                 outSurfaceControl.release();
             }
         }
-        if (outFrames != null) {
-            outFrames.frame.set(0, 0, attrs.width, attrs.height);
-            outFrames.displayFrame.set(outFrames.frame);
-        }
 
         if (outMergedConfiguration != null) {
             outMergedConfiguration.setConfiguration(mConfiguration, mConfiguration);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
index 94aeb2b..5e46023 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SystemWindows.java
@@ -306,7 +306,9 @@
             }
         }
 
-        protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+        @Override
+        protected SurfaceControl getParentSurface(IWindow window,
+                WindowManager.LayoutParams attrs) {
             SurfaceControl leash = new SurfaceControl.Builder(new SurfaceSession())
                   .setContainerLayer()
                   .setName("SystemWindowLeash")
@@ -316,7 +318,7 @@
             synchronized (this) {
                 mLeashForWindow.put(window.asBinder(), leash);
             }
-            b.setParent(leash);
+            return leash;
         }
 
         @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
index a9d3c9f..fcbf9e0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitDecorManager.java
@@ -92,7 +92,7 @@
     }
 
     @Override
-    protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+    protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
         // Can't set position for the ViewRootImpl SC directly. Create a leash to manipulate later.
         final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
                 .setContainerLayer()
@@ -101,7 +101,7 @@
                 .setParent(mHostLeash)
                 .setCallsite("SplitDecorManager#attachToParentSurface");
         mIconLeash = builder.build();
-        b.setParent(mIconLeash);
+        return mIconLeash;
     }
 
     /** Inflates split decor surface on the root surface. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index 5397552..6b5ddcb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -93,7 +93,7 @@
     }
 
     @Override
-    protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+    protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
         // Can't set position for the ViewRootImpl SC directly. Create a leash to manipulate later.
         final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
                 .setContainerLayer()
@@ -103,7 +103,7 @@
         mParentContainerCallbacks.attachToParentSurface(builder);
         mLeash = builder.build();
         mParentContainerCallbacks.onLeashReady(mLeash);
-        b.setParent(mLeash);
+        return mLeash;
     }
 
     /** Inflates {@link DividerView} on to the root surface. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
index face243..2cc9f45 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIWindowManagerAbstract.java
@@ -155,7 +155,7 @@
     }
 
     @Override
-    protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+    protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
         String className = getClass().getSimpleName();
         final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
                 .setContainerLayer()
@@ -164,9 +164,8 @@
                 .setCallsite(className + "#attachToParentSurface");
         attachToParentSurface(builder);
         mLeash = builder.build();
-        b.setParent(mLeash);
-
         initSurface(mLeash);
+        return mLeash;
     }
 
     /** Inits the z-order of the surface. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java
index b310ee2..8ebcd81 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/BackgroundWindowManager.java
@@ -104,7 +104,7 @@
     }
 
     @Override
-    protected void attachToParentSurface(IWindow window, SurfaceControl.Builder b) {
+    protected SurfaceControl getParentSurface(IWindow window, WindowManager.LayoutParams attrs) {
         final SurfaceControl.Builder builder = new SurfaceControl.Builder(new SurfaceSession())
                 .setColorLayer()
                 .setBufferSize(mDisplayBounds.width(), mDisplayBounds.height())
@@ -113,7 +113,7 @@
                 .setName(TAG)
                 .setCallsite("BackgroundWindowManager#attachToParentSurface");
         mLeash = builder.build();
-        b.setParent(mLeash);
+        return mLeash;
     }
 
     /** Inflates background view on to the root surface. */