Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 95a4ed83 authored by Patrick Williams's avatar Patrick Williams
Browse files

WindowlessWindowManager floating window support

Bug: 256993334
Test: go/wm-smoke
Test: atest CtsWindowManagerDeviceTestCases:SurfaceControlViewHostTests
Change-Id: I0d7cad21fa9265a243972b2d65d5f440b530991d
parent 51a4fd95
Loading
Loading
Loading
Loading
+32 −3
Original line number Diff line number Diff line
@@ -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) {
        if (frames.attachedFrame == null) {
            frames.frame.set(0, 0, attrs.width, attrs.height);
        frames.displayFrame.set(frames.frame);
            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.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;
    }
}
+69 −16
Original line number Diff line number Diff line
@@ -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);
        }
        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);
+4 −2
Original line number Diff line number Diff line
@@ -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
+2 −2
Original line number Diff line number Diff line
@@ -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. */
+2 −2
Original line number Diff line number Diff line
@@ -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. */
Loading