diff options
33 files changed, 362 insertions, 304 deletions
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java index b11d74646d67..6f0001dcc0ad 100644 --- a/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java +++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowAddRemovePerfTest.java @@ -84,6 +84,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase private static class TestWindow extends BaseIWindow { final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(); + final InsetsState mRequestedVisibility = new InsetsState(); final Rect mOutFrame = new Rect(); final Rect mOutContentInsets = new Rect(); final Rect mOutStableInsets = new Rect(); @@ -108,7 +109,8 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase long startTime = SystemClock.elapsedRealtimeNanos(); session.addToDisplay(this, mLayoutParams, View.VISIBLE, - Display.DEFAULT_DISPLAY, mOutFrame, mOutContentInsets, mOutStableInsets, + Display.DEFAULT_DISPLAY, mRequestedVisibility, mOutFrame, + mOutContentInsets, mOutStableInsets, mOutDisplayCutout, inputChannel, mOutInsetsState, mOutControls); final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime; state.addExtraResult("add", elapsedTimeNsOfAdd); diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 4d1337b63b19..6a70a856e09a 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -877,9 +877,10 @@ public abstract class WallpaperService extends Service { InputChannel inputChannel = new InputChannel(); if (mSession.addToDisplay(mWindow, mLayout, View.VISIBLE, - mDisplay.getDisplayId(), mWinFrames.frame, mWinFrames.contentInsets, - mWinFrames.stableInsets, mWinFrames.displayCutout, inputChannel, - mInsetsState, mTempControls) < 0) { + mDisplay.getDisplayId(), mInsetsState, mWinFrames.frame, + mWinFrames.contentInsets, mWinFrames.stableInsets, + mWinFrames.displayCutout, inputChannel, mInsetsState, + mTempControls) < 0) { Log.w(TAG, "Failed to add window while updating wallpaper surface."); return; } diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 910fd905296c..7f36169ada50 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -45,12 +45,13 @@ import java.util.List; */ interface IWindowSession { int addToDisplay(IWindow window, in WindowManager.LayoutParams attrs, - in int viewVisibility, in int layerStackId, out Rect outFrame, - out Rect outContentInsets, out Rect outStableInsets, + in int viewVisibility, in int layerStackId, in InsetsState requestedVisibility, + out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets, out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel, out InsetsState insetsState, out InsetsSourceControl[] activeControls); int addToDisplayAsUser(IWindow window, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, in int userId, + in InsetsState requestedVisibility, out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets, out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel, out InsetsState insetsState, out InsetsSourceControl[] activeControls); diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 71899fab554c..878583be87c9 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -212,21 +212,21 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll /** * @return Whether the finish callback of this animation should be invoked. */ - public boolean applyChangeInsets(InsetsState state) { + public boolean applyChangeInsets(@Nullable InsetsState outState) { if (mCancelled) { if (DEBUG) Log.d(TAG, "applyChangeInsets canceled"); return false; } final Insets offset = Insets.subtract(mShownInsets, mPendingInsets); ArrayList<SurfaceParams> params = new ArrayList<>(); - updateLeashesForSide(ISIDE_LEFT, offset.left, mShownInsets.left, mPendingInsets.left, - params, state, mPendingAlpha); - updateLeashesForSide(ISIDE_TOP, offset.top, mShownInsets.top, mPendingInsets.top, params, - state, mPendingAlpha); - updateLeashesForSide(ISIDE_RIGHT, offset.right, mShownInsets.right, mPendingInsets.right, - params, state, mPendingAlpha); - updateLeashesForSide(ISIDE_BOTTOM, offset.bottom, mShownInsets.bottom, - mPendingInsets.bottom, params, state, mPendingAlpha); + updateLeashesForSide(ISIDE_LEFT, offset.left, mPendingInsets.left, params, outState, + mPendingAlpha); + updateLeashesForSide(ISIDE_TOP, offset.top, mPendingInsets.top, params, outState, + mPendingAlpha); + updateLeashesForSide(ISIDE_RIGHT, offset.right, mPendingInsets.right, params, outState, + mPendingAlpha); + updateLeashesForSide(ISIDE_BOTTOM, offset.bottom, mPendingInsets.bottom, params, outState, + mPendingAlpha); mController.applySurfaceParams(params.toArray(new SurfaceParams[params.size()])); mCurrentInsets = mPendingInsets; @@ -357,8 +357,8 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll return alpha >= 1 ? 1 : (alpha <= 0 ? 0 : alpha); } - private void updateLeashesForSide(@InternalInsetsSide int side, int offset, int maxInset, - int inset, ArrayList<SurfaceParams> surfaceParams, InsetsState state, Float alpha) { + private void updateLeashesForSide(@InternalInsetsSide int side, int offset, int inset, + ArrayList<SurfaceParams> surfaceParams, @Nullable InsetsState outState, float alpha) { ArraySet<InsetsSourceControl> items = mSideSourceMap.get(side); if (items == null) { return; @@ -377,8 +377,10 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll ? (mAnimationType == ANIMATION_TYPE_SHOW ? true : !mFinished) : inset != 0; - state.getSource(source.getType()).setVisible(visible); - state.getSource(source.getType()).setFrame(mTmpFrame); + if (outState != null) { + outState.getSource(source.getType()).setVisible(visible); + outState.getSource(source.getType()).setFrame(mTmpFrame); + } // If the system is controlling the insets source, the leash can be null. if (leash != null) { diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java index cc3cd278b267..1307052a25cc 100644 --- a/core/java/android/view/InsetsAnimationThreadControlRunner.java +++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java @@ -44,7 +44,6 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro private final InsetsAnimationControlImpl mControl; private final InsetsAnimationControlCallbacks mOuterCallbacks; private final Handler mMainThreadHandler; - private final InsetsState mState = new InsetsState(); private final InsetsAnimationControlCallbacks mCallbacks = new InsetsAnimationControlCallbacks() { @@ -60,7 +59,7 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro @Override public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) { - mControl.applyChangeInsets(mState); + mControl.applyChangeInsets(null /* outState */); } @Override diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 652781a310b9..5037d9e5bfe8 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -484,7 +484,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation /** The state dispatched from server */ private final InsetsState mLastDispatchedState = new InsetsState(); - /** The state sent to server */ + // TODO: Use other class to represent the requested visibility of each type, because the + // display frame and the frame in each source are not used. + /** The requested visibilities sent to server */ private final InsetsState mRequestedState = new InsetsState(); private final Rect mFrame = new Rect(); @@ -499,6 +501,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private final List<WindowInsetsAnimation> mUnmodifiableTmpRunningAnims = Collections.unmodifiableList(mTmpRunningAnims); private final ArrayList<InsetsAnimationControlImpl> mTmpFinishedControls = new ArrayList<>(); + private final ArraySet<InsetsSourceConsumer> mRequestedVisibilityChanged = new ArraySet<>(); private WindowInsets mLastInsets; private boolean mAnimCallbackScheduled; @@ -640,11 +643,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged"); mHost.notifyInsetsChanged(); } - if (!mState.equals(mLastDispatchedState, true /* excludingCaptionInsets */, - true /* excludeInvisibleIme */)) { - if (DEBUG) Log.d(TAG, "onStateChanged, send state to WM: " + mState); - updateRequestedState(); - } return true; } @@ -808,9 +806,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (hideTypes[0] != 0) { applyAnimation(hideTypes[0], false /* show */, false /* fromIme */); } - if (requestedStateStale) { - updateRequestedState(); - } + + // InsetsSourceConsumer#setControl might change the requested visibility. + updateRequestedVisibility(); } @Override @@ -945,6 +943,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (types == 0) { // nothing to animate. listener.onCancelled(null); + updateRequestedVisibility(); if (DEBUG) Log.d(TAG, "no types to animate in controlAnimationUnchecked"); return; } @@ -980,12 +979,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } }); } + updateRequestedVisibility(); return; } if (typesReady == 0) { if (DEBUG) Log.d(TAG, "No types ready. onCancelled()"); listener.onCancelled(null); + updateRequestedVisibility(); return; } @@ -1010,6 +1011,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } else { hideDirectly(types, false /* animationFinished */, animationType); } + updateRequestedVisibility(); } /** @@ -1177,7 +1179,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } if (stateChanged) { mHost.notifyInsetsChanged(); - updateRequestedState(); } } @@ -1202,7 +1203,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @VisibleForTesting public void notifyVisibilityChanged() { mHost.notifyInsetsChanged(); - updateRequestedState(); } /** @@ -1251,38 +1251,39 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation return ANIMATION_TYPE_NONE; } + @VisibleForTesting + public void onRequestedVisibilityChanged(InsetsSourceConsumer consumer) { + mRequestedVisibilityChanged.add(consumer); + } + /** - * Sends the local visibility state back to window manager if it is changed. + * Sends the requested visibilities to window manager if any of them is changed. */ - private void updateRequestedState() { + private void updateRequestedVisibility() { boolean changed = false; - for (int i = mSourceConsumers.size() - 1; i >= 0; i--) { - final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i); + for (int i = mRequestedVisibilityChanged.size() - 1; i >= 0; i--) { + final InsetsSourceConsumer consumer = mRequestedVisibilityChanged.valueAt(i); final @InternalInsetsType int type = consumer.getType(); if (type == ITYPE_CAPTION_BAR) { continue; } - if (consumer.getControl() != null) { - final InsetsSource localSource = mState.getSource(type); - if (!localSource.equals(mRequestedState.peekSource(type))) { - // Our requested state is stale. Update it here and send it to window manager. - mRequestedState.addSource(new InsetsSource(localSource)); - changed = true; - } - if (!localSource.equals(mLastDispatchedState.peekSource(type))) { - // The server state is not what we expected. This can happen while we don't have - // the control. Since we have the control now, we need to send our request again - // to modify the server state. - changed = true; - } + final boolean requestedVisible = consumer.isRequestedVisible(); + if (requestedVisible != mRequestedState.getSourceOrDefaultVisibility(type)) { + mRequestedState.getSource(type).setVisible(requestedVisible); + changed = true; } } + mRequestedVisibilityChanged.clear(); if (!changed) { return; } mHost.onInsetsModified(mRequestedState); } + InsetsState getRequestedVisibility() { + return mRequestedState; + } + @VisibleForTesting public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme) { if (types == 0) { @@ -1316,6 +1317,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation for (int i = internalTypes.size() - 1; i >= 0; i--) { getSourceConsumer(internalTypes.valueAt(i)).hide(animationFinished, animationType); } + updateRequestedVisibility(); } private void showDirectly(@InsetsType int types) { @@ -1326,6 +1328,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation for (int i = internalTypes.size() - 1; i >= 0; i--) { getSourceConsumer(internalTypes.valueAt(i)).show(false /* fromIme */); } + updateRequestedVisibility(); } /** diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index d7ceaf792198..e4a24ebfe9e4 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -350,6 +350,7 @@ public class InsetsSourceConsumer { if (mRequestedVisible != requestedVisible) { mRequestedVisible = requestedVisible; mIsAnimationPending = false; + mController.onRequestedVisibilityChanged(this); if (DEBUG) Log.d(TAG, "setRequestedVisible: " + requestedVisible); } if (applyLocalVisibilityOverride()) { diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 38441d1745b9..b9f1f6a43992 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -63,8 +63,6 @@ import java.util.StringJoiner; */ public class InsetsState implements Parcelable { - public static final InsetsState EMPTY = new InsetsState(); - /** * Internal representation of inset source types. This is different from the public API in * {@link WindowInsets.Type} as one type from the public API might indicate multiple windows diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 77626c285f2a..80f5c0fb8257 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -1021,8 +1021,10 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); adjustLayoutParamsForCompatibility(mWindowAttributes); + controlInsetsForCompatibility(mWindowAttributes); res = mWindowSession.addToDisplayAsUser(mWindow, mWindowAttributes, - getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrames.frame, + getHostVisibility(), mDisplay.getDisplayId(), userId, + mInsetsController.getRequestedVisibility(), mTmpFrames.frame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mDisplayCutout, inputChannel, mTempInsets, mTempControls); diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java index 90a80cefc54d..8f58df466ee3 100644 --- a/core/java/android/view/ViewRootInsetsControllerHost.java +++ b/core/java/android/view/ViewRootInsetsControllerHost.java @@ -144,7 +144,9 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { @Override public void onInsetsModified(InsetsState insetsState) { try { - mViewRoot.mWindowSession.insetsModified(mViewRoot.mWindow, insetsState); + if (mViewRoot.mAdded) { + mViewRoot.mWindowSession.insetsModified(mViewRoot.mWindow, insetsState); + } } catch (RemoteException e) { Log.e(TAG, "Failed to call insetsModified", e); } diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 0c221eddf1a9..814787347b75 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -130,8 +130,8 @@ public class WindowlessWindowManager implements IWindowSession { */ @Override public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs, - int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, - Rect outStableInsets, + int viewVisibility, int displayId, InsetsState requestedVisibility, Rect outFrame, + Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession) @@ -166,11 +166,11 @@ public class WindowlessWindowManager implements IWindowSession { */ @Override public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, - int viewVisibility, int displayId, int userId, Rect outFrame, - Rect outContentInsets, Rect outStableInsets, + int viewVisibility, int displayId, int userId, InsetsState requestedVisibility, + Rect outFrame, Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { - return addToDisplay(window, attrs, viewVisibility, displayId, + return addToDisplay(window, attrs, viewVisibility, displayId, requestedVisibility, outFrame, outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, outInsetsState, outActiveControls); } diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java index 8412e53060c7..b98ce308ae3b 100644 --- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java +++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java @@ -27,6 +27,7 @@ import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -89,6 +90,7 @@ public class InsetsAnimationControlImplTest { mInsetsState = new InsetsState(); mInsetsState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 500, 100)); mInsetsState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(400, 0, 500, 500)); + doNothing().when(mMockController).onRequestedVisibilityChanged(any()); InsetsSourceConsumer topConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, mInsetsState, () -> mMockTransaction, mMockController); topConsumer.setControl( @@ -130,7 +132,7 @@ public class InsetsAnimationControlImplTest { public void testChangeInsets() { mController.setInsetsAndAlpha(Insets.of(0, 30, 40, 0), 1f /* alpha */, 0f /* fraction */); - mController.applyChangeInsets(new InsetsState()); + mController.applyChangeInsets(null /* outState */); assertEquals(Insets.of(0, 30, 40, 0), mController.getCurrentInsets()); assertEquals(1f, mController.getCurrentAlpha(), 1f - mController.getCurrentAlpha()); @@ -150,7 +152,7 @@ public class InsetsAnimationControlImplTest { public void testChangeAlphaNoInsets() { Insets initialInsets = mController.getCurrentInsets(); mController.setInsetsAndAlpha(null, 0.5f, 0f /* fraction*/); - mController.applyChangeInsets(new InsetsState()); + mController.applyChangeInsets(null /* outState */); assertEquals(0.5f, mController.getCurrentAlpha(), 0.5f - mController.getCurrentAlpha()); assertEquals(initialInsets, mController.getCurrentInsets()); } @@ -158,7 +160,7 @@ public class InsetsAnimationControlImplTest { @Test public void testChangeInsetsAndAlpha() { mController.setInsetsAndAlpha(Insets.of(0, 30, 40, 0), 0.5f, 1f); - mController.applyChangeInsets(new InsetsState()); + mController.applyChangeInsets(null /* outState */); assertEquals(0.5f, mController.getCurrentAlpha(), 0.5f - mController.getCurrentAlpha()); assertEquals(Insets.of(0, 30, 40, 0), mController.getCurrentInsets()); } diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java index cc97eb5988e6..7b84f68c0f2c 100644 --- a/core/tests/coretests/src/android/view/InsetsControllerTest.java +++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java @@ -683,71 +683,15 @@ public class InsetsControllerTest { @Test public void testRequestedState() { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { + final InsetsState state = mTestHost.getRequestedState(); - // The modified state can be controlled when we have control. - mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR)); - mController.hide(statusBars()); - assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); - - // The modified state won't be changed while losing control. - mController.onControlsChanged(null /* activeControls */); - assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); - - // The modified state won't be changed while state changed while we don't have control. - InsetsState newState = new InsetsState(mController.getState(), true /* copySource */); - mController.onStateChanged(newState); - assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); - - // The modified state won't be changed while controlling an insets without having the - // control. - mController.show(statusBars()); - assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); - - // The modified state can be updated while gaining control. - mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR)); - assertTrue(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); - - // The modified state can still be updated if the local state and the requested state - // are the same. - mController.onControlsChanged(null /* activeControls */); - mController.hide(statusBars()); - newState = new InsetsState(mController.getState(), true /* copySource */); - newState.getSource(ITYPE_STATUS_BAR).setVisible(false); - mController.onStateChanged(newState); - mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR)); - assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible()); - - // The modified state will always be updated while receiving IME control if IME is - // requested visible. - mController.getSourceConsumer(ITYPE_IME).show(false /* fromIme */); - newState = new InsetsState(mController.getState(), true /* copySource */); - newState.getSource(ITYPE_IME).setVisible(true); - newState.getSource(ITYPE_IME).setFrame(1, 2, 3, 4); - mController.onStateChanged(newState); - mController.onControlsChanged(createSingletonControl(ITYPE_IME)); - assertEquals(newState.getSource(ITYPE_IME), - mTestHost.getModifiedState().peekSource(ITYPE_IME)); - newState = new InsetsState(mController.getState(), true /* copySource */); - newState.getSource(ITYPE_IME).setVisible(true); - newState.getSource(ITYPE_IME).setFrame(5, 6, 7, 8); - mController.onStateChanged(newState); - mController.onControlsChanged(createSingletonControl(ITYPE_IME)); - assertEquals(newState.getSource(ITYPE_IME), - mTestHost.getModifiedState().peekSource(ITYPE_IME)); - - // The modified frames cannot be updated if there is an animation. - mController.onControlsChanged(createSingletonControl(ITYPE_NAVIGATION_BAR)); - mController.hide(navigationBars()); - newState = new InsetsState(mController.getState(), true /* copySource */); - newState.getSource(ITYPE_NAVIGATION_BAR).getFrame().top--; - mController.onStateChanged(newState); - assertNotEquals(newState.getSource(ITYPE_NAVIGATION_BAR), - mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR)); + mController.hide(statusBars() | navigationBars()); + assertFalse(state.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)); + assertFalse(state.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); - // The modified frames can be updated while the animation is done. - mController.cancelExistingAnimations(); - assertEquals(newState.getSource(ITYPE_NAVIGATION_BAR), - mTestHost.getModifiedState().peekSource(ITYPE_NAVIGATION_BAR)); + mController.show(statusBars() | navigationBars()); + assertTrue(state.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR)); + assertTrue(state.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR)); }); } @@ -878,7 +822,7 @@ public class InsetsControllerTest { public static class TestHost extends ViewRootInsetsControllerHost { - private InsetsState mModifiedState = new InsetsState(); + private final InsetsState mRequestedState = new InsetsState(); TestHost(ViewRootImpl viewRoot) { super(viewRoot); @@ -886,12 +830,12 @@ public class InsetsControllerTest { @Override public void onInsetsModified(InsetsState insetsState) { - mModifiedState = new InsetsState(insetsState, true /* copySource */); + mRequestedState.set(insetsState, true); super.onInsetsModified(insetsState); } - public InsetsState getModifiedState() { - return mModifiedState; + public InsetsState getRequestedState() { + return mRequestedState; } } } diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 858cce49d1c1..834046062191 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -69,21 +69,27 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final LongSparseArray<LocalDisplayDevice> mDevices = new LongSparseArray<>(); - @SuppressWarnings("unused") // Becomes active at instantiation time. - private PhysicalDisplayEventReceiver mPhysicalDisplayEventReceiver; + private final Injector mInjector; // Called with SyncRoot lock held. public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, Context context, Handler handler, Listener listener) { + this(syncRoot, context, handler, listener, new Injector()); + } + + LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot, + Context context, Handler handler, Listener listener, Injector injector) { super(syncRoot, context, handler, listener, TAG); + mInjector = injector; } @Override public void registerLocked() { super.registerLocked(); - mPhysicalDisplayEventReceiver = new PhysicalDisplayEventReceiver(getHandler().getLooper()); + mInjector.setDisplayEventListenerLocked(getHandler().getLooper(), + new LocalDisplayEventListener()); for (long physicalDisplayId : SurfaceControl.getPhysicalDisplayIds()) { tryConnectDisplayLocked(physicalDisplayId); @@ -1052,12 +1058,33 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } - private final class PhysicalDisplayEventReceiver extends DisplayEventReceiver { - PhysicalDisplayEventReceiver(Looper looper) { + public static class Injector { + private ProxyDisplayEventReceiver mReceiver; + public void setDisplayEventListenerLocked(Looper looper, DisplayEventListener listener) { + mReceiver = new ProxyDisplayEventReceiver(looper, listener); + } + } + + public interface DisplayEventListener { + void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected); + void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId); + } + + public static final class ProxyDisplayEventReceiver extends DisplayEventReceiver { + private final DisplayEventListener mListener; + ProxyDisplayEventReceiver(Looper looper, DisplayEventListener listener) { super(looper, VSYNC_SOURCE_APP, CONFIG_CHANGED_EVENT_DISPATCH); + mListener = listener; } + public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { + mListener.onHotplug(timestampNanos, physicalDisplayId, connected); + } + public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) { + mListener.onConfigChanged(timestampNanos, physicalDisplayId, configId); + } + } - @Override + private final class LocalDisplayEventListener implements DisplayEventListener { public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { synchronized (getSyncRoot()) { if (connected) { @@ -1067,8 +1094,6 @@ final class LocalDisplayAdapter extends DisplayAdapter { } } } - - @Override public void onConfigChanged(long timestampNanos, long physicalDisplayId, int configId) { if (DEBUG) { Slog.d(TAG, "onConfigChanged(" diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index b06d77076326..4a30ca96abb6 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -192,6 +192,8 @@ import android.view.IWindow; import android.view.InputChannel; import android.view.InputDevice; import android.view.InputWindowHandle; +import android.view.InsetsSource; +import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.MagnificationSpec; import android.view.RemoteAnimationDefinition; @@ -4830,7 +4832,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp boolean ignoreRequest) { final int type = win.mAttrs.type; final boolean stickyHideNav = - !win.getRequestedInsetsState().getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR) + !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR) && win.mAttrs.insetsFlags.behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; return (!stickyHideNav || ignoreRequest) && type != TYPE_INPUT_METHOD && type != TYPE_NOTIFICATION_SHADE && win.getActivityType() != ACTIVITY_TYPE_HOME; @@ -5557,6 +5559,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp class RemoteInsetsControlTarget implements InsetsControlTarget { private final IDisplayWindowInsetsController mRemoteInsetsController; + private final InsetsState mRequestedInsetsState = new InsetsState(); RemoteInsetsControlTarget(IDisplayWindowInsetsController controller) { mRemoteInsetsController = controller; @@ -5612,6 +5615,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp Slog.w(TAG, "Failed to deliver showInsets", e); } } + + @Override + public boolean getRequestedVisibility(@InternalInsetsType int type) { + return mRequestedInsetsState.getSourceOrDefaultVisibility(type); + } + + void updateRequestedVisibility(InsetsState state) { + for (int i = 0; i < InsetsState.SIZE; i++) { + final InsetsSource source = state.peekSource(i); + if (source == null) continue; + mRequestedInsetsState.addSource(source); + } + } } /** diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java index 4e7e0ba99ff1..b2cf856b9228 100644 --- a/services/core/java/com/android/server/wm/DisplayPolicy.java +++ b/services/core/java/com/android/server/wm/DisplayPolicy.java @@ -1659,10 +1659,8 @@ public class DisplayPolicy { provider != null ? provider.getControlTarget() : null; final WindowState navControllingWin = navControlTarget instanceof WindowState ? (WindowState) navControlTarget : null; - final InsetsState requestedState = navControllingWin != null - ? navControllingWin.getRequestedInsetsState() : null; - final boolean navVisible = requestedState != null - ? requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR) + final boolean navVisible = navControllingWin != null + ? navControllingWin.getRequestedVisibility(ITYPE_NAVIGATION_BAR) : InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR); final boolean showBarsByTouch = navControllingWin != null && navControllingWin.mAttrs.insetsFlags.behavior == BEHAVIOR_SHOW_BARS_BY_TOUCH; @@ -2073,11 +2071,10 @@ public class DisplayPolicy { // the cutout safe zone. if (cutoutMode != LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS) { final boolean attachedInParent = attached != null && !layoutInScreen; - final InsetsState requestedInsetsState = win.getRequestedInsetsState(); final boolean requestedFullscreen = (fl & FLAG_FULLSCREEN) != 0 - || !requestedInsetsState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR); + || !win.getRequestedVisibility(ITYPE_STATUS_BAR); final boolean requestedHideNavigation = - !requestedInsetsState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR); + !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR); // TYPE_BASE_APPLICATION windows are never considered floating here because they don't // get cropped / shifted to the displayFrame in WindowState. @@ -2423,14 +2420,8 @@ public class DisplayPolicy { } final LayoutParams attrs = mTopFullscreenOpaqueWindowState.getAttrs(); final int fl = attrs.flags; - final InsetsSource request = mTopFullscreenOpaqueWindowState.getRequestedInsetsState() - .peekSource(ITYPE_STATUS_BAR); - if (WindowManagerDebugConfig.DEBUG) { - Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrame()); - Slog.d(TAG, "attr: " + attrs + " request: " + request); - } return (fl & LayoutParams.FLAG_FULLSCREEN) != 0 - || (request != null && !request.isVisible()); + || !mTopFullscreenOpaqueWindowState.getRequestedVisibility(ITYPE_STATUS_BAR); } /** @@ -2864,18 +2855,15 @@ public class DisplayPolicy { return; } - final InsetsState requestedState = controlTarget.getRequestedInsetsState(); final @InsetsType int restorePositionTypes = - (requestedState.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR) + (controlTarget.getRequestedVisibility(ITYPE_NAVIGATION_BAR) ? Type.navigationBars() : 0) - | (requestedState.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR) + | (controlTarget.getRequestedVisibility(ITYPE_STATUS_BAR) ? Type.statusBars() : 0) - | (mExtraNavBarAlt != null - && requestedState.getSourceOrDefaultVisibility( + | (mExtraNavBarAlt != null && controlTarget.getRequestedVisibility( ITYPE_EXTRA_NAVIGATION_BAR) ? Type.navigationBars() : 0) - | (mClimateBarAlt != null - && requestedState.getSourceOrDefaultVisibility( + | (mClimateBarAlt != null && controlTarget.getRequestedVisibility( ITYPE_CLIMATE_BAR) ? Type.statusBars() : 0); @@ -2981,12 +2969,11 @@ public class DisplayPolicy { win.mAttrs.insetsFlags.appearance, mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState, mDisplayContent.mInputMethodWindow, navColorWin) | opaqueAppearance; - final InsetsState requestedInsets = win.getRequestedInsetsState(); final int behavior = win.mAttrs.insetsFlags.behavior; final boolean isImmersive = behavior == BEHAVIOR_SHOW_BARS_BY_SWIPE || behavior == BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE; - final boolean isFullscreen = !requestedInsets.getSourceOrDefaultVisibility(ITYPE_STATUS_BAR) - || !requestedInsets.getSourceOrDefaultVisibility(ITYPE_NAVIGATION_BAR); + final boolean isFullscreen = !win.getRequestedVisibility(ITYPE_STATUS_BAR) + || !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR); if (mLastDisableFlags == disableFlags && mLastAppearance == appearance && mLastFullscreenAppearance == fullscreenAppearance @@ -3152,10 +3139,7 @@ public class DisplayPolicy { freeformStackVisible, resizing, fullscreenDrawsNavBarBackground, dockedDrawsNavigationBarBackground); - final InsetsState requestedInsetsState = win.getRequestedInsetsState(); - final boolean requestHideNavBar = !requestedInsetsState.getSourceOrDefaultVisibility( - ITYPE_NAVIGATION_BAR); - + final boolean requestHideNavBar = !win.getRequestedVisibility(ITYPE_NAVIGATION_BAR); final long now = SystemClock.uptimeMillis(); final boolean pendingPanic = mPendingPanicGestureUptime != 0 && now - mPendingPanicGestureUptime <= PANIC_GESTURE_EXPIRATION; diff --git a/services/core/java/com/android/server/wm/InsetsControlTarget.java b/services/core/java/com/android/server/wm/InsetsControlTarget.java index 5e7ed3f80e43..287dd74e62c7 100644 --- a/services/core/java/com/android/server/wm/InsetsControlTarget.java +++ b/services/core/java/com/android/server/wm/InsetsControlTarget.java @@ -18,6 +18,7 @@ package com.android.server.wm; import android.inputmethodservice.InputMethodService; import android.view.InsetsState; +import android.view.InsetsState.InternalInsetsType; import android.view.WindowInsets.Type.InsetsType; /** @@ -39,10 +40,10 @@ interface InsetsControlTarget { } /** - * @return The requested {@link InsetsState} of this target. + * @return The requested visibility of this target. */ - default InsetsState getRequestedInsetsState() { - return InsetsState.EMPTY; + default boolean getRequestedVisibility(@InternalInsetsType int type) { + return InsetsState.getDefaultVisibility(type); } /** diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java index 361788497e11..bd05da9fe50a 100644 --- a/services/core/java/com/android/server/wm/InsetsPolicy.java +++ b/services/core/java/com/android/server/wm/InsetsPolicy.java @@ -173,13 +173,7 @@ class InsetsPolicy { // animation frame which will be triggered if a new leash is created. mDisplayContent.mWmService.mAnimator.getChoreographer().postFrameCallback(time -> { synchronized (mDisplayContent.mWmService.mGlobalLock) { - final InsetsState state = new InsetsState(mStateController.getRawInsetsState()); - startAnimation(true /* show */, () -> { - synchronized (mDisplayContent.mWmService.mGlobalLock) { - mStateController.notifyInsetsChanged(); - } - }, state); - mStateController.onInsetsModified(mDummyControlTarget, state); + startAnimation(true /* show */, null /* callback */); } }); } @@ -189,15 +183,18 @@ class InsetsPolicy { if (mShowingTransientTypes.size() == 0) { return; } - InsetsState state = new InsetsState(mStateController.getRawInsetsState()); startAnimation(false /* show */, () -> { synchronized (mDisplayContent.mWmService.mGlobalLock) { + for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { + // We are about to clear mShowingTransientTypes, we don't want the transient bar + // can cause insets on the client. Restore the client visibility. + final @InternalInsetsType int type = mShowingTransientTypes.get(i); + mStateController.getSourceProvider(type).setClientVisible(false); + } mShowingTransientTypes.clear(); - mStateController.notifyInsetsChanged(); updateBarControlTarget(mFocusedWin); } - }, state); - mStateController.onInsetsModified(mDummyControlTarget, state); + }); } boolean isTransient(@InternalInsetsType int type) { @@ -211,7 +208,7 @@ class InsetsPolicy { final InsetsState originalState = mStateController.getInsetsForDispatch(target); InsetsState state = originalState; for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { - final int type = mShowingTransientTypes.get(i); + final @InternalInsetsType int type = mShowingTransientTypes.get(i); final InsetsSource originalSource = state.peekSource(type); if (originalSource != null && originalSource.isVisible()) { if (state == originalState) { @@ -227,26 +224,25 @@ class InsetsPolicy { return state; } - void onInsetsModified(WindowState windowState, InsetsState state) { - mStateController.onInsetsModified(windowState, state); - checkAbortTransient(windowState, state); + void onInsetsModified(InsetsControlTarget caller) { + mStateController.onInsetsModified(caller); + checkAbortTransient(caller); updateBarControlTarget(mFocusedWin); } /** - * Called when a window modified the insets state. If the window set a insets source to visible - * while it is shown transiently, we need to abort the transient state. + * Called when a control target modified the insets state. If the target set a insets source to + * visible while it is shown transiently, we need to abort the transient state. * - * @param windowState who changed the insets state. - * @param state the modified insets state. + * @param caller who changed the insets state. */ - private void checkAbortTransient(WindowState windowState, InsetsState state) { + private void checkAbortTransient(InsetsControlTarget caller) { if (mShowingTransientTypes.size() != 0) { IntArray abortTypes = new IntArray(); for (int i = mShowingTransientTypes.size() - 1; i >= 0; i--) { - final int type = mShowingTransientTypes.get(i); - if (mStateController.isFakeTarget(type, windowState) - && state.getSource(type).isVisible()) { + final @InternalInsetsType int type = mShowingTransientTypes.get(i); + if (mStateController.isFakeTarget(type, caller) + && caller.getRequestedVisibility(type)) { mShowingTransientTypes.remove(i); abortTypes.add(type); } @@ -393,12 +389,12 @@ class InsetsPolicy { } @VisibleForTesting - void startAnimation(boolean show, Runnable callback, InsetsState state) { + void startAnimation(boolean show, Runnable callback) { int typesReady = 0; final SparseArray<InsetsSourceControl> controls = new SparseArray<>(); final IntArray showingTransientTypes = mShowingTransientTypes; for (int i = showingTransientTypes.size() - 1; i >= 0; i--) { - int type = showingTransientTypes.get(i); + final @InternalInsetsType int type = showingTransientTypes.get(i); InsetsSourceProvider provider = mStateController.getSourceProvider(type); InsetsSourceControl control = provider.getControl(mDummyControlTarget); if (control == null || control.getLeash() == null) { @@ -406,7 +402,6 @@ class InsetsPolicy { } typesReady |= InsetsState.toPublicType(type); controls.put(control.getType(), new InsetsSourceControl(control)); - state.setSourceVisible(type, show); } controlAnimationUnchecked(typesReady, controls, show, callback); } @@ -428,12 +423,9 @@ class InsetsPolicy { mId = id; } - private void updateVisibility(InsetsControlTarget controlTarget, + private void updateVisibility(@Nullable InsetsControlTarget controlTarget, @InternalInsetsType int type) { - final WindowState controllingWin = - controlTarget instanceof WindowState ? (WindowState) controlTarget : null; - setVisible(controllingWin == null - || controllingWin.getRequestedInsetsState().getSourceOrDefaultVisibility(type)); + setVisible(controlTarget == null || controlTarget.getRequestedVisibility(type)); } private void setVisible(boolean visible) { @@ -463,7 +455,9 @@ class InsetsPolicy { @Override protected void onAnimationFinish() { super.onAnimationFinish(); - DisplayThread.getHandler().post(mFinishCallback); + if (mFinishCallback != null) { + DisplayThread.getHandler().post(mFinishCallback); + } } private class InsetsPolicyAnimationControlCallbacks implements @@ -484,7 +478,7 @@ class InsetsPolicy { mAnimatingShown = show; mAnimationControl = new InsetsAnimationControlImpl(controls, - mFocusedWin.getDisplayContent().getBounds(), getState(), + mFocusedWin.getDisplayContent().getBounds(), mFocusedWin.getInsetsState(), mListener, typesReady, this, mListener.getDurationMs(), InsetsController.SYSTEM_BARS_INTERPOLATOR, show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE); @@ -495,8 +489,7 @@ class InsetsPolicy { /** Called on SurfaceAnimationThread without global WM lock held. */ @Override public void scheduleApplyChangeInsets(InsetsAnimationControlRunner runner) { - InsetsState state = getState(); - if (mAnimationControl.applyChangeInsets(state)) { + if (mAnimationControl.applyChangeInsets(null /* outState */)) { mAnimationControl.finish(mAnimatingShown); } } @@ -507,20 +500,6 @@ class InsetsPolicy { // onAnimationFinished callback. } - /** - * This method will return a state with fullscreen frame override. No need to make copy - * after getting state from this method. - * @return The client insets state with full display frame override. - */ - private InsetsState getState() { - // To animate the transient animation correctly, we need to let the state hold - // the full display frame. - InsetsState overrideState = new InsetsState(mFocusedWin.getRequestedInsetsState(), - true); - overrideState.setDisplayFrame(mFocusedWin.getDisplayContent().getBounds()); - return overrideState; - } - /** Called on SurfaceAnimationThread without global WM lock held. */ @Override public void applySurfaceParams( diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index 7defc5ddb3f4..e83151dae161 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -338,11 +338,12 @@ class InsetsSourceProvider { } } - boolean onInsetsModified(InsetsControlTarget caller, InsetsSource modifiedSource) { - if (mControlTarget != caller || modifiedSource.isVisible() == mClientVisible) { + boolean updateClientVisibility(InsetsControlTarget caller) { + final boolean requestedVisible = caller.getRequestedVisibility(mSource.getType()); + if (caller != mControlTarget || requestedVisible == mClientVisible) { return false; } - setClientVisible(modifiedSource.isVisible()); + setClientVisible(requestedVisible); return true; } @@ -350,7 +351,7 @@ class InsetsSourceProvider { mIsLeashReadyForDispatching = true; } - private void setClientVisible(boolean clientVisible) { + void setClientVisible(boolean clientVisible) { if (mClientVisible == clientVisible) { return; } diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index b59452ffaf36..b9c2093fe435 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -289,16 +289,10 @@ class InsetsStateController { winInsetsChanged.clear(); } - void onInsetsModified(InsetsControlTarget windowState, InsetsState state) { + void onInsetsModified(InsetsControlTarget caller) { boolean changed = false; - for (int i = 0; i < InsetsState.SIZE; i++) { - final InsetsSource source = state.peekSource(i); - if (source == null) continue; - final InsetsSourceProvider provider = mProviders.get(source.getType()); - if (provider == null) { - continue; - } - changed |= provider.onInsetsModified(windowState, source); + for (int i = mProviders.size() - 1; i >= 0; i--) { + changed |= mProviders.valueAt(i).updateClientVisibility(caller); } if (changed) { notifyInsetsChanged(); @@ -464,11 +458,24 @@ class InsetsStateController { final InsetsSourceProvider provider = mProviders.valueAt(i); provider.onSurfaceTransactionApplied(); } + final ArraySet<InsetsControlTarget> newControlTargets = new ArraySet<>(); for (int i = mPendingControlChanged.size() - 1; i >= 0; i--) { final InsetsControlTarget controlTarget = mPendingControlChanged.valueAt(i); controlTarget.notifyInsetsControlChanged(); + if (mControlTargetTypeMap.containsKey(controlTarget)) { + // We only collect targets who get controls, not lose controls. + newControlTargets.add(controlTarget); + } } mPendingControlChanged.clear(); + + // This updates the insets visibilities AFTER sending current insets state and controls + // to the clients, so that the clients can change the current visibilities to the + // requested visibilities with animations. + for (int i = newControlTargets.size() - 1; i >= 0; i--) { + onInsetsModified(newControlTargets.valueAt(i)); + } + newControlTargets.clear(); }); } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 02230d6ae2a6..f84e70eec675 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -92,6 +92,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { private float mLastReportedAnimatorScale; private String mPackageName; private String mRelayoutTag; + private final InsetsState mDummyRequestedVisibility = new InsetsState(); private final InsetsSourceControl[] mDummyControls = new InsetsSourceControl[0]; public Session(WindowManagerService service, IWindowSessionCallback callback) { @@ -158,25 +159,26 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { @Override public int addToDisplay(IWindow window, WindowManager.LayoutParams attrs, - int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, - Rect outStableInsets, + int viewVisibility, int displayId, InsetsState requestedVisibility, Rect outFrame, + Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { - return mService.addWindow(this, window, attrs, viewVisibility, displayId, outFrame, + return mService.addWindow(this, window, attrs, viewVisibility, displayId, + UserHandle.getUserId(mUid), requestedVisibility, outFrame, outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, - outInsetsState, outActiveControls, UserHandle.getUserId(mUid)); + outInsetsState, outActiveControls); } @Override public int addToDisplayAsUser(IWindow window, WindowManager.LayoutParams attrs, - int viewVisibility, int displayId, int userId, Rect outFrame, - Rect outContentInsets, Rect outStableInsets, + int viewVisibility, int displayId, int userId, InsetsState requestedVisibility, + Rect outFrame, Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { - return mService.addWindow(this, window, attrs, viewVisibility, displayId, outFrame, - outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, - outInsetsState, outActiveControls, userId); + return mService.addWindow(this, window, attrs, viewVisibility, displayId, userId, + requestedVisibility, outFrame, outContentInsets, outStableInsets, outDisplayCutout, + outInputChannel, outInsetsState, outActiveControls); } @Override @@ -184,9 +186,10 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, InsetsState outInsetsState) { return mService.addWindow(this, window, attrs, viewVisibility, displayId, + UserHandle.getUserId(mUid), mDummyRequestedVisibility, new Rect() /* outFrame */, outContentInsets, outStableInsets, new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */, - outInsetsState, mDummyControls, UserHandle.getUserId(mUid)); + outInsetsState, mDummyControls); } @Override @@ -493,9 +496,8 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { final WindowState windowState = mService.windowForClientLocked(this, window, false /* throwOnError */); if (windowState != null) { - windowState.updateRequestedInsetsState(state); - windowState.getDisplayContent().getInsetsPolicy().onInsetsModified( - windowState, state); + windowState.updateRequestedVisibility(state); + windowState.getDisplayContent().getInsetsPolicy().onInsetsModified(windowState); } } } diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java index 87b470a54f77..01adb8b35c3b 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotController.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java @@ -482,8 +482,7 @@ class TaskSnapshotController { final int color = ColorUtils.setAlphaComponent( task.getTaskDescription().getBackgroundColor(), 255); final LayoutParams attrs = mainWindow.getAttrs(); - final InsetsState insetsState = new InsetsState(mainWindow.getInsetsState()); - mergeInsetsSources(insetsState, mainWindow.getRequestedInsetsState()); + final InsetsState insetsState = getInsetsStateWithVisibilityOverride(mainWindow); final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrame(), insetsState); final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags, attrs.privateFlags, attrs.insetsFlags.appearance, task.getTaskDescription(), @@ -603,13 +602,18 @@ class TaskSnapshotController { return 0; } - static void mergeInsetsSources(InsetsState base, InsetsState other) { + static InsetsState getInsetsStateWithVisibilityOverride(WindowState win) { + final InsetsState state = new InsetsState(win.getInsetsState()); for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) { - final InsetsSource source = other.peekSource(type); - if (source != null) { - base.addSource(source); + final boolean requestedVisible = win.getRequestedVisibility(type); + InsetsSource source = state.peekSource(type); + if (source != null && source.isVisible() != requestedVisible) { + source = new InsetsSource(source); + source.setVisible(requestedVisible); + state.addSource(source); } } + return state; } static Rect getSystemBarInsets(Rect frame, InsetsState state) { diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java index efa05255a415..e8c4491d3677 100644 --- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java +++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java @@ -42,8 +42,8 @@ import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_AT import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES; import static com.android.internal.policy.DecorView.getNavigationBarRect; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; +import static com.android.server.wm.TaskSnapshotController.getInsetsStateWithVisibilityOverride; import static com.android.server.wm.TaskSnapshotController.getSystemBarInsets; -import static com.android.server.wm.TaskSnapshotController.mergeInsetsSources; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; @@ -236,14 +236,15 @@ class TaskSnapshotSurface implements StartingSurface { task.getBounds(taskBounds); currentOrientation = topFullscreenOpaqueWindow.getConfiguration().orientation; activityType = activity.getActivityType(); - insetsState = new InsetsState(topFullscreenOpaqueWindow.getInsetsState()); - mergeInsetsSources(insetsState, topFullscreenOpaqueWindow.getRequestedInsetsState()); + insetsState = getInsetsStateWithVisibilityOverride(topFullscreenOpaqueWindow); + } try { final int res = session.addToDisplay(window, layoutParams, - View.GONE, activity.getDisplayContent().getDisplayId(), tmpFrames.frame, - tmpFrames.contentInsets, tmpFrames.stableInsets, tmpFrames.displayCutout, - null /* outInputChannel */, mTmpInsetsState, mTempControls); + View.GONE, activity.getDisplayContent().getDisplayId(), mTmpInsetsState, + tmpFrames.frame, tmpFrames.contentInsets, tmpFrames.stableInsets, + tmpFrames.displayCutout, null /* outInputChannel */, mTmpInsetsState, + mTempControls); if (res < 0) { Slog.w(TAG, "Failed to add snapshot starting window res=" + res); return null; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 26655f4326a9..40b770fc67ec 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1375,10 +1375,10 @@ public class WindowManagerService extends IWindowManager.Stub } public int addWindow(Session session, IWindow client, LayoutParams attrs, int viewVisibility, - int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, + int displayId, int requestUserId, InsetsState requestedVisibility, Rect outFrame, + Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, - InsetsState outInsetsState, InsetsSourceControl[] outActiveControls, - int requestUserId) { + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { Arrays.fill(outActiveControls, null); int[] appOp = new int[1]; final boolean isRoundedCornerOverlay = (attrs.privateFlags @@ -1573,6 +1573,7 @@ public class WindowManagerService extends IWindowManager.Stub final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy(); displayPolicy.adjustWindowParamsLw(win, win.mAttrs, callingPid, callingUid); + win.updateRequestedVisibility(requestedVisibility); res = displayPolicy.validateAddingWindowLw(attrs, callingPid, callingUid); if (res != WindowManagerGlobal.ADD_OKAY) { @@ -4034,8 +4035,8 @@ public class WindowManagerService extends IWindowManager.Stub if (dc == null || dc.mRemoteInsetsControlTarget == null) { return; } - dc.getInsetsStateController().onInsetsModified( - dc.mRemoteInsetsControlTarget, state); + dc.mRemoteInsetsControlTarget.updateRequestedVisibility(state); + dc.getInsetsStateController().onInsetsModified(dc.mRemoteInsetsControlTarget); } } finally { Binder.restoreCallingIdentity(origId); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 25b48281db8e..90c3d6cb85af 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -224,6 +224,7 @@ import android.view.InputEventReceiver; import android.view.InputWindowHandle; import android.view.InsetsSource; import android.view.InsetsState; +import android.view.InsetsState.InternalInsetsType; import android.view.Surface.Rotation; import android.view.SurfaceControl; import android.view.SurfaceSession; @@ -719,20 +720,20 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private final WindowProcessController mWpcForDisplayConfigChanges; /** - * @return The insets state as requested by the client, i.e. the dispatched insets state - * for which the visibilities are overridden with what the client requested. + * Returns the visibility of the given {@link InternalInsetsType type} requested by the client. + * + * @param type the given {@link InternalInsetsType type}. + * @return {@code true} if the type is requested visible. */ @Override - public InsetsState getRequestedInsetsState() { - return mRequestedInsetsState; + public boolean getRequestedVisibility(@InternalInsetsType int type) { + return mRequestedInsetsState.getSourceOrDefaultVisibility(type); } /** - * @see #getRequestedInsetsState() + * @see #getRequestedVisibility(int) */ - void updateRequestedInsetsState(InsetsState state) { - - // Only update the sources the client is actually controlling. + void updateRequestedVisibility(InsetsState state) { for (int i = 0; i < InsetsState.SIZE; i++) { final InsetsSource source = state.peekSource(i); if (source == null) continue; diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java index 9d2393b4a8f7..0ab15017a2b4 100644 --- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java @@ -83,6 +83,8 @@ public class LocalDisplayAdapterTest { private LinkedList<DisplayAddress.Physical> mAddresses = new LinkedList<>(); + private Injector mInjector; + @Before public void setUp() throws Exception { mMockitoSession = mockitoSession() @@ -94,8 +96,9 @@ public class LocalDisplayAdapterTest { doReturn(mMockedResources).when(mMockedContext).getResources(); LocalServices.removeServiceForTest(LightsManager.class); LocalServices.addService(LightsManager.class, mMockedLightsManager); + mInjector = new Injector(); mAdapter = new LocalDisplayAdapter(mMockedSyncRoot, mMockedContext, mHandler, - mListener); + mListener, mInjector); spyOn(mAdapter); doReturn(mMockedContext).when(mAdapter).getOverlayContext(); } @@ -222,7 +225,7 @@ public class LocalDisplayAdapterTest { display.configs = configs; display.activeConfig = 1; setUpDisplay(display); - mAdapter.registerLocked(); + mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); assertThat(SurfaceControl.getActiveConfig(display.token)).isEqualTo(1); @@ -272,7 +275,7 @@ public class LocalDisplayAdapterTest { new int[Display.HdrCapabilities.HDR_TYPE_HDR10_PLUS], 1000, 1000, 0); display.hdrCapabilities = changedHdrCapabilities; setUpDisplay(display); - mAdapter.registerLocked(); + mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); assertThat(mListener.addedDisplays.size()).isEqualTo(1); @@ -308,7 +311,7 @@ public class LocalDisplayAdapterTest { final int[] changedColorModes = new int[]{Display.COLOR_MODE_DEFAULT}; display.colorModes = changedColorModes; setUpDisplay(display); - mAdapter.registerLocked(); + mInjector.getTransmitter().sendHotplug(display, /* connected */ true); waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); assertThat(mListener.addedDisplays.size()).isEqualTo(1); @@ -322,6 +325,35 @@ public class LocalDisplayAdapterTest { assertThat(displayDeviceInfo.supportedColorModes).isEqualTo(changedColorModes); } + @Test + public void testDisplayChange_withStaleDesiredDisplayConfigSpecs() throws Exception { + SurfaceControl.DisplayConfig[] configs = new SurfaceControl.DisplayConfig[]{ + createFakeDisplayConfig(1920, 1080, 60f), + createFakeDisplayConfig(1920, 1080, 50f) + }; + final int activeConfig = 0; + FakeDisplay display = new FakeDisplay(PORT_A, configs, activeConfig); + display.desiredDisplayConfigSpecs.defaultConfig = 1; + + setUpDisplay(display); + updateAvailableDisplays(); + mAdapter.registerLocked(); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); + + // Change the display + display.configs = new SurfaceControl.DisplayConfig[]{ + createFakeDisplayConfig(1920, 1080, 60f) + }; + // SurfaceFlinger can return a stale defaultConfig. Make sure this doesn't + // trigger ArrayOutOfBoundsException. + display.desiredDisplayConfigSpecs.defaultConfig = 1; + + setUpDisplay(display); + updateAvailableDisplays(); + mInjector.getTransmitter().sendHotplug(display, /* connected */ true); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); + } + private void assertDisplayDpi(DisplayDeviceInfo info, int expectedPort, float expectedXdpi, float expectedYDpi, @@ -356,6 +388,8 @@ public class LocalDisplayAdapterTest { public int[] colorModes = new int[]{ Display.COLOR_MODE_DEFAULT }; public Display.HdrCapabilities hdrCapabilities = new Display.HdrCapabilities(new int[0], 1000, 1000, 0); + public SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs = + new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f, 60.f, 60.f); private FakeDisplay(int port) { this.address = createDisplayAddress(port); @@ -387,7 +421,7 @@ public class LocalDisplayAdapterTest { () -> SurfaceControl.getDisplayColorModes(display.token)); doReturn(display.hdrCapabilities).when( () -> SurfaceControl.getHdrCapabilities(display.token)); - doReturn(new SurfaceControl.DesiredDisplayConfigSpecs(0, 60.f, 60.f, 60.f, 60.f)) + doReturn(display.desiredDisplayConfigSpecs) .when(() -> SurfaceControl.getDesiredDisplayConfigSpecs(display.token)); } @@ -422,7 +456,7 @@ public class LocalDisplayAdapterTest { return config; } - private void waitForHandlerToComplete(Handler handler, long waitTimeMs) + private static void waitForHandlerToComplete(Handler handler, long waitTimeMs) throws InterruptedException { final Object lock = new Object(); synchronized (lock) { @@ -435,6 +469,35 @@ public class LocalDisplayAdapterTest { } } + private class HotplugTransmitter { + private final Handler mHandler; + private final LocalDisplayAdapter.DisplayEventListener mListener; + + HotplugTransmitter(Looper looper, LocalDisplayAdapter.DisplayEventListener listener) { + mHandler = new Handler(looper); + mListener = listener; + } + + public void sendHotplug(FakeDisplay display, boolean connected) + throws InterruptedException { + mHandler.post(() -> mListener.onHotplug(/* timestampNanos = */ 0, + display.address.getPhysicalDisplayId(), connected)); + waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS); + } + } + + private class Injector extends LocalDisplayAdapter.Injector { + private HotplugTransmitter mTransmitter; + @Override + public void setDisplayEventListenerLocked(Looper looper, + LocalDisplayAdapter.DisplayEventListener listener) { + mTransmitter = new HotplugTransmitter(looper, listener); + } + public HotplugTransmitter getTransmitter() { + return mTransmitter; + } + } + private class TestListener implements DisplayAdapter.Listener { public ArrayList<DisplayDevice> addedDisplays = new ArrayList<>(); public ArrayList<DisplayDevice> changedDisplays = new ArrayList<>(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index dd85484605d1..ad9692f404e9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -1523,7 +1523,8 @@ public class ActivityRecordTests extends WindowTestsBase { // Return error to skip unnecessary operation. doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay( any() /* window */, any() /* attrs */, - anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* outFrame */, + anyInt() /* viewVisibility */, anyInt() /* displayId */, + any() /* requestedVisibility */, any() /* outFrame */, any() /* outContentInsets */, any() /* outStableInsets */, any() /* outDisplayCutout */, any() /* outInputChannel */, any() /* outInsetsState */, any() /* outActiveControls */); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java index 2920c1da3f24..5a14a249e78f 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java @@ -522,7 +522,9 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mWindow.mAttrs.setFitInsetsTypes(0 /* types */); mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow) .getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false); - mWindow.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).setVisible(false); + final InsetsState requestedState = new InsetsState(); + requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false); + mWindow.updateRequestedVisibility(requestedState); addWindow(mWindow); mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */); @@ -544,7 +546,9 @@ public class DisplayPolicyLayoutTests extends DisplayPolicyTestsBase { mWindow.mAttrs.setFitInsetsTypes(0 /* types */); mDisplayContent.getInsetsPolicy().getInsetsForDispatch(mWindow) .getSource(InsetsState.ITYPE_STATUS_BAR).setVisible(false); - mWindow.getRequestedInsetsState().getSource(ITYPE_STATUS_BAR).setVisible(false); + final InsetsState requestedState = new InsetsState(); + requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false); + mWindow.updateRequestedVisibility(requestedState); mWindow.mAttrs.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; addWindow(mWindow); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java index a55423a7baf6..21bdc9e7785e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java @@ -313,8 +313,8 @@ public class DisplayPolicyTests extends WindowTestsBase { // App requests to hide navigation bar. final InsetsState requestedState = new InsetsState(); requestedState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false); - mAppWindow.updateRequestedInsetsState(requestedState); - insetsPolicy.onInsetsModified(mAppWindow, requestedState); + mAppWindow.updateRequestedVisibility(requestedState); + insetsPolicy.onInsetsModified(mAppWindow); assertNotNull(displayPolicy.mInputConsumer); // App still requests to hide navigation bar, but without BEHAVIOR_SHOW_BARS_BY_TOUCH. diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java index 8c02faf7ac09..d67120f53917 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsPolicyTest.java @@ -38,7 +38,6 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; @@ -180,7 +179,7 @@ public class InsetsPolicyTest extends WindowTestsBase { final WindowState fullscreenApp = addWindow(TYPE_APPLICATION, "fullscreenApp"); final InsetsState requestedState = new InsetsState(); requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false); - fullscreenApp.updateRequestedInsetsState(requestedState); + fullscreenApp.updateRequestedVisibility(requestedState); // Add a non-fullscreen dialog window. final WindowState dialog = addWindow(TYPE_APPLICATION, "dialog"); @@ -215,7 +214,7 @@ public class InsetsPolicyTest extends WindowTestsBase { final WindowState newFocusedFullscreenApp = addWindow(TYPE_APPLICATION, "newFullscreenApp"); final InsetsState newRequestedState = new InsetsState(); newRequestedState.getSource(ITYPE_STATUS_BAR).setVisible(true); - newFocusedFullscreenApp.updateRequestedInsetsState(newRequestedState); + newFocusedFullscreenApp.updateRequestedVisibility(newRequestedState); // Make sure status bar is hidden by previous insets state. mDisplayContent.getInsetsPolicy().updateBarControlTarget(fullscreenApp); @@ -232,20 +231,28 @@ public class InsetsPolicyTest extends WindowTestsBase { @UseTestDisplay(addWindows = W_ACTIVITY) @Test public void testShowTransientBars_bothCanBeTransient_appGetsBothFakeControls() { - addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar") - .getControllableInsetProvider().getSource().setVisible(false); - addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar") - .getControllableInsetProvider().getSource().setVisible(false); + final WindowState statusBar = addNonFocusableWindow(TYPE_STATUS_BAR, "statusBar"); + statusBar.setHasSurface(true); + statusBar.getControllableInsetProvider().setServerVisible(true); + final WindowState navBar = addNonFocusableWindow(TYPE_NAVIGATION_BAR, "navBar"); + navBar.setHasSurface(true); + navBar.getControllableInsetProvider().setServerVisible(true); final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy()); + doNothing().when(policy).startAnimation(anyBoolean(), any()); - doAnswer(invocation -> { - ((InsetsState) invocation.getArgument(2)).setSourceVisible(ITYPE_STATUS_BAR, true); - ((InsetsState) invocation.getArgument(2)).setSourceVisible(ITYPE_NAVIGATION_BAR, true); - return null; - }).when(policy).startAnimation(anyBoolean(), any(), any()); - + // Make both system bars invisible. + final InsetsState requestedState = new InsetsState(); + requestedState.getSource(ITYPE_STATUS_BAR).setVisible(false); + requestedState.getSource(ITYPE_NAVIGATION_BAR).setVisible(false); + mAppWindow.updateRequestedVisibility(requestedState); policy.updateBarControlTarget(mAppWindow); + waitUntilWindowAnimatorIdle(); + assertFalse(mDisplayContent.getInsetsStateController().getRawInsetsState() + .getSource(ITYPE_STATUS_BAR).isVisible()); + assertFalse(mDisplayContent.getInsetsStateController().getRawInsetsState() + .getSource(ITYPE_NAVIGATION_BAR).isVisible()); + policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}); waitUntilWindowAnimatorIdle(); final InsetsSourceControl[] controls = @@ -272,7 +279,7 @@ public class InsetsPolicyTest extends WindowTestsBase { .getControllableInsetProvider().setServerVisible(true); final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy()); - doNothing().when(policy).startAnimation(anyBoolean(), any(), any()); + doNothing().when(policy).startAnimation(anyBoolean(), any()); policy.updateBarControlTarget(mAppWindow); policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}); waitUntilWindowAnimatorIdle(); @@ -301,7 +308,7 @@ public class InsetsPolicyTest extends WindowTestsBase { .getControllableInsetProvider().getSource().setVisible(false); final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy()); - doNothing().when(policy).startAnimation(anyBoolean(), any(), any()); + doNothing().when(policy).startAnimation(anyBoolean(), any()); policy.updateBarControlTarget(mAppWindow); policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}); waitUntilWindowAnimatorIdle(); @@ -326,7 +333,8 @@ public class InsetsPolicyTest extends WindowTestsBase { assertTrue(state.getSource(ITYPE_STATUS_BAR).isVisible()); assertTrue(state.getSource(ITYPE_NAVIGATION_BAR).isVisible()); - policy.onInsetsModified(mAppWindow, state); + mAppWindow.updateRequestedVisibility(state); + policy.onInsetsModified(mAppWindow); waitUntilWindowAnimatorIdle(); controls = mDisplayContent.getInsetsStateController().getControlsForDispatch(mAppWindow); @@ -348,7 +356,7 @@ public class InsetsPolicyTest extends WindowTestsBase { final WindowState app2 = addWindow(TYPE_APPLICATION, "app"); final InsetsPolicy policy = spy(mDisplayContent.getInsetsPolicy()); - doNothing().when(policy).startAnimation(anyBoolean(), any(), any()); + doNothing().when(policy).startAnimation(anyBoolean(), any()); policy.updateBarControlTarget(app); policy.showTransient(new int[]{ITYPE_STATUS_BAR, ITYPE_NAVIGATION_BAR}); final InsetsSourceControl[] controls = 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 a0fa9369e7a8..983063125ce9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java @@ -205,7 +205,8 @@ public class InsetsSourceProviderTest extends WindowTestsBase { mProvider.updateControlForTarget(target, false /* force */); InsetsState state = new InsetsState(); state.getSource(ITYPE_STATUS_BAR).setVisible(false); - mProvider.onInsetsModified(target, state.getSource(ITYPE_STATUS_BAR)); + target.updateRequestedVisibility(state); + mProvider.updateClientVisibility(target); assertFalse(mSource.isVisible()); } @@ -217,7 +218,8 @@ public class InsetsSourceProviderTest extends WindowTestsBase { mProvider.setWindow(statusBar, null, null); InsetsState state = new InsetsState(); state.getSource(ITYPE_STATUS_BAR).setVisible(false); - mProvider.onInsetsModified(target, state.getSource(ITYPE_STATUS_BAR)); + target.updateRequestedVisibility(state); + mProvider.updateClientVisibility(target); assertTrue(mSource.isVisible()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java index e2cd8a909266..c14df676f525 100644 --- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java @@ -189,8 +189,8 @@ public class InsetsStateControllerTest extends WindowTestsBase { getController().onImeControlTargetChanged(mDisplayContent.mInputMethodInputTarget); final InsetsState requestedState = new InsetsState(); requestedState.getSource(ITYPE_IME).setVisible(true); - mDisplayContent.mInputMethodInputTarget.updateRequestedInsetsState(requestedState); - getController().onInsetsModified(mDisplayContent.mInputMethodInputTarget, requestedState); + mDisplayContent.mInputMethodInputTarget.updateRequestedVisibility(requestedState); + getController().onInsetsModified(mDisplayContent.mInputMethodInputTarget); // Send our spy window (app) into the system so that we can detect the invocation. final WindowState win = createWindow(null, TYPE_APPLICATION, "app"); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index c18043fcc4b9..19bed48a4bc5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -71,7 +71,7 @@ import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import android.util.Size; import android.view.DisplayCutout; -import android.view.InsetsSource; +import android.view.InsetsState; import android.view.SurfaceControl; import android.view.WindowManager; @@ -426,10 +426,11 @@ public class WindowStateTests extends WindowTestsBase { .setWindow(statusBar, null /* frameProvider */, null /* imeFrameProvider */); mDisplayContent.getInsetsStateController().onBarControlTargetChanged( app, null /* fakeTopControlling */, app, null /* fakeNavControlling */); - final InsetsSource source = new InsetsSource(ITYPE_STATUS_BAR); - source.setVisible(false); + final InsetsState state = new InsetsState(); + state.getSource(ITYPE_STATUS_BAR).setVisible(false); + app.updateRequestedVisibility(state); mDisplayContent.getInsetsStateController().getSourceProvider(ITYPE_STATUS_BAR) - .onInsetsModified(app, source); + .updateClientVisibility(app); waitUntilHandlersIdle(); assertFalse(statusBar.isVisible()); } |