Merge "WindowlessWindowManager floating window support"

This commit is contained in:
Patrick Williams
2023-01-09 22:23:58 +00:00
committed by Android (Google) Code Review
7 changed files with 113 additions and 30 deletions

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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. */

View File

@@ -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. */

View File

@@ -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. */

View File

@@ -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. */