Merge "Ensure the requested insets state is up to date" into rvc-dev am: b8ad491e6d am: 282a713b1a am: 29ea59f79c

Change-Id: I55195138a008466a2d465c75da0f7c9f20c931ca
This commit is contained in:
Tiger Huang
2020-04-30 18:25:53 +00:00
committed by Automerger Merge Worker
2 changed files with 78 additions and 20 deletions

View File

@@ -22,8 +22,6 @@ import static android.view.InsetsState.toInternalType;
import static android.view.InsetsState.toPublicType;
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED;
import android.animation.AnimationHandler;
import android.animation.Animator;
@@ -43,7 +41,6 @@ import android.util.SparseArray;
import android.view.InsetsSourceConsumer.ShowResult;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
import android.view.ViewTreeObserver.OnPreDrawListener;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimation.Bounds;
@@ -424,8 +421,14 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private final String TAG = "InsetsControllerImpl";
/** The local state */
private final InsetsState mState = new InsetsState();
private final InsetsState mLastDispachedState = new InsetsState();
/** The state dispatched from server */
private final InsetsState mLastDispatchedState = new InsetsState();
/** The state sent to server */
private final InsetsState mRequestedState = new InsetsState();
private final Rect mFrame = new Rect();
private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator;
@@ -539,24 +542,24 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
public InsetsState getLastDispatchedState() {
return mLastDispachedState;
return mLastDispatchedState;
}
@VisibleForTesting
public boolean onStateChanged(InsetsState state) {
boolean localStateChanged = !mState.equals(state, true /* excludingCaptionInsets */)
|| !captionInsetsUnchanged();
if (!localStateChanged && mLastDispachedState.equals(state)) {
if (!localStateChanged && mLastDispatchedState.equals(state)) {
return false;
}
updateState(state);
mLastDispachedState.set(state, true /* copySources */);
mLastDispatchedState.set(state, true /* copySources */);
applyLocalVisibilityOverride();
if (localStateChanged) {
mHost.notifyInsetsChanged();
}
if (!mState.equals(mLastDispachedState, true /* excludingCaptionInsets */)) {
sendStateToWindowManager();
if (!mState.equals(mLastDispatchedState, true /* excludingCaptionInsets */)) {
updateRequestedState();
}
return true;
}
@@ -629,8 +632,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
}
int[] showTypes = new int[1];
int[] hideTypes = new int[1];
final boolean hasControl = mTmpControlArray.size() > 0;
final int[] showTypes = new int[1];
final int[] hideTypes = new int[1];
// Ensure to update all existing source consumers
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
@@ -663,6 +667,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (hideTypes[0] != 0) {
applyAnimation(hideTypes[0], false /* show */, false /* fromIme */);
}
if (hasControl) {
// We might have changed our requested visibilities while we don't have the control,
// so we need to update our requested state once we have control. Otherwise, our
// requested state at the server side might be incorrect.
updateRequestedState();
}
}
@Override
@@ -992,7 +1002,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting
public void notifyVisibilityChanged() {
mHost.notifyInsetsChanged();
sendStateToWindowManager();
updateRequestedState();
}
/**
@@ -1042,18 +1052,28 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}
/**
* Sends the local visibility state back to window manager.
* Sends the local visibility state back to window manager if it is changed.
*/
private void sendStateToWindowManager() {
InsetsState tmpState = new InsetsState();
private void updateRequestedState() {
boolean changed = false;
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
if (consumer.getType() == ITYPE_CAPTION_BAR) continue;
final @InternalInsetsType int type = consumer.getType();
if (type == ITYPE_CAPTION_BAR) {
continue;
}
if (consumer.getControl() != null) {
tmpState.addSource(mState.getSource(consumer.getType()));
final InsetsSource localSource = mState.getSource(type);
if (!localSource.equals(mRequestedState.peekSource(type))) {
mRequestedState.addSource(new InsetsSource(localSource));
changed = true;
}
}
}
mHost.onInsetsModified(tmpState);
if (!changed) {
return;
}
mHost.onInsetsModified(mRequestedState);
}
@VisibleForTesting

View File

@@ -93,6 +93,7 @@ public class InsetsControllerTest {
private SurfaceSession mSession = new SurfaceSession();
private SurfaceControl mLeash;
private ViewRootImpl mViewRoot;
private TestHost mTestHost;
private TestHandler mTestHandler;
private OffsettableClock mTestClock;
private static InsetsModeSession sInsetsModeSession;
@@ -123,8 +124,8 @@ public class InsetsControllerTest {
}
mTestClock = new OffsettableClock();
mTestHandler = new TestHandler(null, mTestClock);
mController = new InsetsController(new ViewRootInsetsControllerHost(mViewRoot),
(controller, type) -> {
mTestHost = new TestHost(mViewRoot);
mController = new InsetsController(mTestHost, (controller, type) -> {
if (type == ITYPE_IME) {
return new InsetsSourceConsumer(type, controller.getState(),
Transaction::new, controller) {
@@ -686,6 +687,24 @@ public class InsetsControllerTest {
});
}
@Test
public void testRequestedState() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
mController.hide(statusBars());
assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
mController.onControlsChanged(new InsetsSourceControl[0]);
assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
InsetsState newState = new InsetsState(mController.getState(), true /* copySource */);
mController.onStateChanged(newState);
assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
mController.show(statusBars());
assertFalse(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
mController.onControlsChanged(createSingletonControl(ITYPE_STATUS_BAR));
assertTrue(mTestHost.getModifiedState().peekSource(ITYPE_STATUS_BAR).isVisible());
});
}
private void waitUntilNextFrame() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
Choreographer.getMainThreadInstance().postCallback(Choreographer.CALLBACK_COMMIT,
@@ -717,4 +736,23 @@ public class InsetsControllerTest {
mController.onControlsChanged(controls);
return controls;
}
private static class TestHost extends ViewRootInsetsControllerHost {
private InsetsState mModifiedState = new InsetsState();
TestHost(ViewRootImpl viewRoot) {
super(viewRoot);
}
@Override
public void onInsetsModified(InsetsState insetsState) {
mModifiedState = new InsetsState(insetsState, true /* copySource */);
super.onInsetsModified(insetsState);
}
public InsetsState getModifiedState() {
return mModifiedState;
}
}
}