From a12ea56ba413a9bde19255be62cf6d12f228444a Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Mon, 7 Jan 2019 17:47:47 +0100 Subject: [PATCH] Window Manager Flag Migration (3/n) Adds fake control which is an InsetsSourceControl without a leash in it. Fake control will be sent to the client when bars are shown transiently. So the client thinks it still have the control over the bars, but moving the bars won't take effect. InsetsController.show still works and dispatches the modified state to the server. The server can then listen to that state change, and abort transient showing mode, start a new animation, and send over the new control with an actual leash to the client. Bug: 118118435 Test: atest InsetsSourceProviderTest InsetsStateControllerTest WindowStateTests Change-Id: I8db5942e9f951e2652d4a3a34c9fde2efe5b9858 --- .../view/InsetsAnimationControlImpl.java | 9 ++- .../android/view/InsetsSourceConsumer.java | 2 +- .../android/view/InsetsSourceControl.java | 13 +++- .../server/wm/InsetsSourceProvider.java | 27 +++++++- .../server/wm/InsetsStateController.java | 61 ++++++++++++++++--- .../server/wm/InsetsSourceProviderTest.java | 32 +++++++--- 6 files changed, 117 insertions(+), 27 deletions(-) diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 50ef91f909977..341c2147c64a1 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -26,7 +26,6 @@ import android.annotation.Nullable; import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; -import android.os.UidProto.Sync; import android.util.ArraySet; import android.util.SparseArray; import android.util.SparseIntArray; @@ -40,7 +39,6 @@ import android.view.WindowManager.LayoutParams; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; -import java.util.function.Function; import java.util.function.Supplier; /** @@ -238,7 +236,12 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll addTranslationToMatrix(side, offset, mTmpMatrix, mTmpFrame); state.getSource(source.getType()).setFrame(mTmpFrame); - surfaceParams.add(new SurfaceParams(leash, 1f, mTmpMatrix, null, 0, 0f, inset != 0)); + + // If the system is controlling the insets source, the leash can be null. + if (leash != null) { + surfaceParams.add(new SurfaceParams(leash, 1f /* alpha */, mTmpMatrix, + null /* windowCrop */, 0 /* layer */, 0f /* cornerRadius*/, inset != 0)); + } } } diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index 9edccb3fb221b..08d45a746dc41 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -167,7 +167,7 @@ public class InsetsSourceConsumer { } private void applyHiddenToControl() { - if (mSourceControl == null) { + if (mSourceControl == null || mSourceControl.getLeash() == null) { return; } diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java index 4940981748a8b..4919074ec252e 100644 --- a/core/java/android/view/InsetsSourceControl.java +++ b/core/java/android/view/InsetsSourceControl.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.Nullable; import android.graphics.Point; import android.os.Parcel; import android.os.Parcelable; @@ -28,10 +29,10 @@ import android.view.InsetsState.InternalInsetType; public class InsetsSourceControl implements Parcelable { private final @InternalInsetType int mType; - private final SurfaceControl mLeash; + private final @Nullable SurfaceControl mLeash; private final Point mSurfacePosition; - public InsetsSourceControl(@InternalInsetType int type, SurfaceControl leash, + public InsetsSourceControl(@InternalInsetType int type, @Nullable SurfaceControl leash, Point surfacePosition) { mType = type; mLeash = leash; @@ -42,7 +43,13 @@ public class InsetsSourceControl implements Parcelable { return mType; } - public SurfaceControl getLeash() { + /** + * Gets the leash for controlling insets source. If the system is controlling the insets source, + * for example, transient bars, the client will receive fake controls without leash in it. + * + * @return the leash. + */ + public @Nullable SurfaceControl getLeash() { return mLeash; } diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 1b7b92bca2507..34253ed6fc8cd 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -51,8 +51,11 @@ class InsetsSourceProvider { private final @NonNull InsetsSource mSource; private final DisplayContent mDisplayContent; private final InsetsStateController mStateController; + private final InsetsSourceControl mFakeControl; private @Nullable InsetsSourceControl mControl; private @Nullable InsetsControlTarget mControlTarget; + private @Nullable InsetsControlTarget mFakeControlTarget; + private @Nullable ControlAdapter mAdapter; private WindowState mWin; private TriConsumer mFrameProvider; @@ -73,6 +76,8 @@ class InsetsSourceProvider { mSource = source; mDisplayContent = displayContent; mStateController = stateController; + mFakeControl = new InsetsSourceControl(source.getType(), null /* leash */, + new Point()); final int type = source.getType(); if (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR) { @@ -150,6 +155,16 @@ class InsetsSourceProvider { && !mWin.mGivenInsetsPending); } + /** + * @see InsetsStateController#onControlFakeTargetChanged(int, InsetsControlTarget) + */ + void updateControlForFakeTarget(@Nullable InsetsControlTarget fakeTarget) { + if (fakeTarget == mFakeControlTarget) { + return; + } + mFakeControlTarget = fakeTarget; + } + void updateControlForTarget(@Nullable InsetsControlTarget target, boolean force) { if (mWin == null) { mControlTarget = target; @@ -199,8 +214,14 @@ class InsetsSourceProvider { mSource.setVisible(mServerVisible && mClientVisible); } - InsetsSourceControl getControl() { - return mControl; + InsetsSourceControl getControl(InsetsControlTarget target) { + if (target == mControlTarget) { + return mControl; + } + if (target == mFakeControlTarget) { + return mFakeControl; + } + return null; } boolean isClientVisible() { @@ -257,5 +278,5 @@ class InsetsSourceProvider { @Override public void writeToProto(ProtoOutputStream proto) { } - }; + } } diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index bb704957a55a1..4ebb553318e8e 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -20,6 +20,8 @@ import static android.view.InsetsState.InternalInsetType; import static android.view.InsetsState.TYPE_IME; import static android.view.InsetsState.TYPE_NAVIGATION_BAR; import static android.view.InsetsState.TYPE_TOP_BAR; +import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; +import static android.view.ViewRootImpl.sNewInsetsMode; import android.annotation.NonNull; import android.annotation.Nullable; @@ -47,6 +49,10 @@ class InsetsStateController { private final ArrayMap> mControlTargetTypeMap = new ArrayMap<>(); private final SparseArray mTypeControlTargetMap = new SparseArray<>(); + + /** @see #onControlFakeTargetChanged */ + private final SparseArray mTypeFakeControlTargetMap = new SparseArray<>(); + private final ArraySet mPendingControlChanged = new ArraySet<>(); private final Consumer mDispatchInsetsChanged = w -> { @@ -93,7 +99,7 @@ class InsetsStateController { final int size = controlled.size(); final InsetsSourceControl[] result = new InsetsSourceControl[size]; for (int i = 0; i < size; i++) { - result[i] = mProviders.get(controlled.get(i)).getControl(); + result[i] = mProviders.get(controlled.get(i)).getControl(target); } return result; } @@ -157,7 +163,8 @@ class InsetsStateController { void notifyControlRevoked(@NonNull InsetsControlTarget previousControlTarget, InsetsSourceProvider provider) { - removeFromControlMaps(previousControlTarget, provider.getSource().getType()); + removeFromControlMaps(previousControlTarget, provider.getSource().getType(), + false /* fake */); } private void onControlChanged(@InternalInsetType int type, @@ -175,17 +182,47 @@ class InsetsStateController { } provider.updateControlForTarget(target, false /* force */); if (previous != null) { - removeFromControlMaps(previous, type); + removeFromControlMaps(previous, type, false /* fake */); mPendingControlChanged.add(previous); } if (target != null) { - addToControlMaps(target, type); + addToControlMaps(target, type, false /* fake */); mPendingControlChanged.add(target); } } + /** + * The fake target saved here will be used to pretend to the app that it's still under control + * of the bars while it's not really, but we still need to find out the apps intentions around + * showing/hiding. For example, when the transient bars are showing, and the fake target + * requests to show system bars, the transient state will be aborted. + */ + void onControlFakeTargetChanged(@InternalInsetType int type, + @Nullable InsetsControlTarget fakeTarget) { + if (sNewInsetsMode != NEW_INSETS_MODE_FULL) { + return; + } + final InsetsControlTarget previous = mTypeFakeControlTargetMap.get(type); + if (fakeTarget == previous) { + return; + } + final InsetsSourceProvider provider = mProviders.get(type); + if (provider == null) { + return; + } + provider.updateControlForFakeTarget(fakeTarget); + if (previous != null) { + removeFromControlMaps(previous, type, true /* fake */); + mPendingControlChanged.add(previous); + } + if (fakeTarget != null) { + addToControlMaps(fakeTarget, type, true /* fake */); + mPendingControlChanged.add(fakeTarget); + } + } + private void removeFromControlMaps(@NonNull InsetsControlTarget target, - @InternalInsetType int type) { + @InternalInsetType int type, boolean fake) { final ArrayList array = mControlTargetTypeMap.get(target); if (array == null) { return; @@ -194,15 +231,23 @@ class InsetsStateController { if (array.isEmpty()) { mControlTargetTypeMap.remove(target); } - mTypeControlTargetMap.remove(type); + if (fake) { + mTypeFakeControlTargetMap.remove(type); + } else { + mTypeControlTargetMap.remove(type); + } } private void addToControlMaps(@NonNull InsetsControlTarget target, - @InternalInsetType int type) { + @InternalInsetType int type, boolean fake) { final ArrayList array = mControlTargetTypeMap.computeIfAbsent(target, key -> new ArrayList<>()); array.add(type); - mTypeControlTargetMap.put(type, target); + if (fake) { + mTypeFakeControlTargetMap.put(type, target); + } else { + mTypeControlTargetMap.put(type, target); + } } void notifyControlChanged(InsetsControlTarget target) { diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java index 86ee75ebf3df1..3e2e4382a68cb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -31,14 +31,15 @@ import android.platform.test.annotations.Presubmit; import android.view.InsetsSource; import android.view.InsetsState; -import androidx.test.filters.FlakyTest; import androidx.test.filters.SmallTest; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; @SmallTest @Presubmit +@RunWith(WindowTestRunner.class) public class InsetsSourceProviderTest extends WindowTestsBase { private InsetsSource mSource = new InsetsSource(TYPE_TOP_BAR); @@ -53,7 +54,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { @Test public void testPostLayout() { - final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar"); topBar.getFrameLw().set(0, 0, 500, 100); topBar.mHasSurface = true; mProvider.setWindow(topBar, null); @@ -66,7 +67,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { @Test public void testPostLayout_invisible() { - final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar"); topBar.getFrameLw().set(0, 0, 500, 100); mProvider.setWindow(topBar, null); mProvider.onPostLayout(); @@ -76,7 +77,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { @Test public void testPostLayout_frameProvider() { - final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar"); topBar.getFrameLw().set(0, 0, 500, 100); mProvider.setWindow(topBar, (displayFrames, windowState, rect) -> { @@ -88,19 +89,32 @@ public class InsetsSourceProviderTest extends WindowTestsBase { @Test public void testUpdateControlForTarget() { - final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); topBar.getFrameLw().set(0, 0, 500, 100); mProvider.setWindow(topBar, null); mProvider.updateControlForTarget(target, false /* force */); - assertNotNull(mProvider.getControl()); + assertNotNull(mProvider.getControl(target)); mProvider.updateControlForTarget(null, false /* force */); - assertNull(mProvider.getControl()); + assertNull(mProvider.getControl(target)); + } + + @Test + public void testUpdateControlForFakeTarget() { + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar"); + final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); + topBar.getFrameLw().set(0, 0, 500, 100); + mProvider.setWindow(topBar, null); + mProvider.updateControlForFakeTarget(target); + assertNotNull(mProvider.getControl(target)); + assertNull(mProvider.getControl(target).getLeash()); + mProvider.updateControlForFakeTarget(null); + assertNull(mProvider.getControl(target)); } @Test public void testInsetsModified() { - final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); topBar.getFrameLw().set(0, 0, 500, 100); mProvider.setWindow(topBar, null); @@ -113,7 +127,7 @@ public class InsetsSourceProviderTest extends WindowTestsBase { @Test public void testInsetsModified_noControl() { - final WindowState topBar = createWindow(null, TYPE_APPLICATION, "parentWindow"); + final WindowState topBar = createWindow(null, TYPE_APPLICATION, "topBar"); final WindowState target = createWindow(null, TYPE_APPLICATION, "target"); topBar.getFrameLw().set(0, 0, 500, 100); mProvider.setWindow(topBar, null);