diff --git a/core/java/android/view/WindowlessWindowLayout.java b/core/java/android/view/WindowlessWindowLayout.java index 8ef4d7874f028..6fb01f2a78234 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 @@ public class WindowlessWindowLayout extends WindowLayout { 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 ecb555735b277..021193e8d9184 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 @@ public class WindowlessWindowManager implements IWindowSession { 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 @@ public class WindowlessWindowManager implements IWindowSession { 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 @@ public class WindowlessWindowManager implements IWindowSession { } } - 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 @@ public class WindowlessWindowManager implements IWindowSession { 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 @@ public class WindowlessWindowManager implements IWindowSession { } 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 @@ public class WindowlessWindowManager implements IWindowSession { "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 @@ public class WindowlessWindowManager implements IWindowSession { "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 @@ public class WindowlessWindowManager implements IWindowSession { } 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 94aeb2beb1e08..5e46023cd84f1 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 @@ public class SystemWindows { } } - 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 @@ public class SystemWindows { 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 a9d3c9f154cde..fcbf9e0812b01 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 @@ public class SplitDecorManager extends WindowlessWindowManager { } @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 @@ public class SplitDecorManager extends WindowlessWindowManager { .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 5397552cbe8e1..6b5ddcb7ebe3a 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 @@ public final class SplitWindowManager extends WindowlessWindowManager { } @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 @@ public final class SplitWindowManager extends WindowlessWindowManager { 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 face24340a4e5..2cc9f45d1e9d0 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 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana } @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 @@ public abstract class CompatUIWindowManagerAbstract extends WindowlessWindowMana .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 b310ee2095bff..8ebcd815cf12f 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 @@ public final class BackgroundWindowManager extends WindowlessWindowManager { } @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 @@ public final class BackgroundWindowManager extends WindowlessWindowManager { .setName(TAG) .setCallsite("BackgroundWindowManager#attachToParentSurface"); mLeash = builder.build(); - b.setParent(mLeash); + return mLeash; } /** Inflates background view on to the root surface. */