Merge "Only create InsetsSourceConsumer for InsetsSourceControl" into udc-dev am: ab6927cf18

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/24239788

Change-Id: I3d561fd84fc72f9753c8ac2c41f016570f6a4cd5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Treehugger Robot
2023-08-18 10:01:32 +00:00
committed by Automerger Merge Worker
4 changed files with 58 additions and 57 deletions

View File

@@ -69,6 +69,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.graphics.SfVsyncFrameCallbackProvider; import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
import com.android.internal.inputmethod.ImeTracing; import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.SoftInputShowHideReason; import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.util.function.TriFunction;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
@@ -77,7 +78,6 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.BiFunction;
/** /**
* Implements {@link WindowInsetsController} on the client. * Implements {@link WindowInsetsController} on the client.
@@ -621,7 +621,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
private final InsetsState mLastDispatchedState = new InsetsState(); private final InsetsState mLastDispatchedState = new InsetsState();
private final Rect mFrame = new Rect(); private final Rect mFrame = new Rect();
private final BiFunction<InsetsController, InsetsSource, InsetsSourceConsumer> mConsumerCreator; private final TriFunction<InsetsController, Integer, Integer, InsetsSourceConsumer>
mConsumerCreator;
private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>(); private final SparseArray<InsetsSourceConsumer> mSourceConsumers = new SparseArray<>();
private final InsetsSourceConsumer mImeSourceConsumer; private final InsetsSourceConsumer mImeSourceConsumer;
private final Host mHost; private final Host mHost;
@@ -689,13 +690,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
// Don't change the indexes of the sources while traversing. Remove it later. // Don't change the indexes of the sources while traversing. Remove it later.
mPendingRemoveIndexes.add(index1); mPendingRemoveIndexes.add(index1);
// Remove the consumer as well except the IME one. IME consumer should always
// be there since we need to communicate with InputMethodManager no matter we
// have the source or not.
if (source1.getType() != ime()) {
mSourceConsumers.remove(source1.getId());
}
} }
@Override @Override
@@ -750,12 +744,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}; };
public InsetsController(Host host) { public InsetsController(Host host) {
this(host, (controller, source) -> { this(host, (controller, id, type) -> {
if (source.getType() == ime()) { if (type == ime()) {
return new ImeInsetsSourceConsumer(source.getId(), controller.mState, return new ImeInsetsSourceConsumer(id, controller.mState,
Transaction::new, controller); Transaction::new, controller);
} else { } else {
return new InsetsSourceConsumer(source.getId(), source.getType(), controller.mState, return new InsetsSourceConsumer(id, type, controller.mState,
Transaction::new, controller); Transaction::new, controller);
} }
}, host.getHandler()); }, host.getHandler());
@@ -763,7 +757,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@VisibleForTesting @VisibleForTesting
public InsetsController(Host host, public InsetsController(Host host,
BiFunction<InsetsController, InsetsSource, InsetsSourceConsumer> consumerCreator, TriFunction<InsetsController, Integer, Integer, InsetsSourceConsumer> consumerCreator,
Handler handler) { Handler handler) {
mHost = host; mHost = host;
mConsumerCreator = consumerCreator; mConsumerCreator = consumerCreator;
@@ -815,7 +809,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
}; };
// Make mImeSourceConsumer always non-null. // Make mImeSourceConsumer always non-null.
mImeSourceConsumer = getSourceConsumer(new InsetsSource(ID_IME, ime())); mImeSourceConsumer = getSourceConsumer(ID_IME, ime());
} }
@VisibleForTesting @VisibleForTesting
@@ -893,7 +887,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
cancelledUserAnimationTypes[0] |= type; cancelledUserAnimationTypes[0] |= type;
} }
} }
getSourceConsumer(source).updateSource(source, animationType); final InsetsSourceConsumer consumer = mSourceConsumers.get(source.getId());
if (consumer != null) {
consumer.updateSource(source, animationType);
} else {
mState.addSource(source);
}
existingTypes |= type; existingTypes |= type;
if (source.isVisible()) { if (source.isVisible()) {
visibleTypes |= type; visibleTypes |= type;
@@ -997,8 +996,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
@InsetsType int controllableTypes = 0; @InsetsType int controllableTypes = 0;
int consumedControlCount = 0; int consumedControlCount = 0;
final int[] showTypes = new int[1]; final @InsetsType int[] showTypes = new int[1];
final int[] hideTypes = new int[1]; final @InsetsType int[] hideTypes = new int[1];
// Ensure to update all existing source consumers // Ensure to update all existing source consumers
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) { for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
@@ -1014,15 +1013,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
consumer.setControl(control, showTypes, hideTypes); consumer.setControl(control, showTypes, hideTypes);
} }
// Ensure to create source consumers if not available yet.
if (consumedControlCount != mTmpControlArray.size()) { if (consumedControlCount != mTmpControlArray.size()) {
// Whoops! The server sent us some controls without sending corresponding sources.
for (int i = mTmpControlArray.size() - 1; i >= 0; i--) { for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
final InsetsSourceControl control = mTmpControlArray.valueAt(i); final InsetsSourceControl control = mTmpControlArray.valueAt(i);
final InsetsSourceConsumer consumer = mSourceConsumers.get(control.getId()); getSourceConsumer(control.getId(), control.getType())
if (consumer == null) { .setControl(control, showTypes, hideTypes);
control.release(SurfaceControl::release);
Log.e(TAG, control + " has no consumer.");
}
} }
} }
@@ -1587,6 +1583,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
if (type == ime()) { if (type == ime()) {
abortPendingImeControlRequest(); abortPendingImeControlRequest();
} }
if (consumer.getType() != ime()) {
// IME consumer should always be there since we need to communicate with
// InputMethodManager no matter we have the control or not.
mSourceConsumers.remove(consumer.getId());
}
} }
private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) { private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) {
@@ -1640,21 +1641,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
} }
@VisibleForTesting @VisibleForTesting
public @NonNull InsetsSourceConsumer getSourceConsumer(InsetsSource source) { public @NonNull InsetsSourceConsumer getSourceConsumer(int id, int type) {
final int sourceId = source.getId(); InsetsSourceConsumer consumer = mSourceConsumers.get(id);
InsetsSourceConsumer consumer = mSourceConsumers.get(sourceId);
if (consumer != null) { if (consumer != null) {
return consumer; return consumer;
} }
if (source.getType() == ime() && mImeSourceConsumer != null) { if (type == ime() && mImeSourceConsumer != null) {
// WindowInsets.Type.ime() should be only provided by one source. // WindowInsets.Type.ime() should be only provided by one source.
mSourceConsumers.remove(mImeSourceConsumer.getId()); mSourceConsumers.remove(mImeSourceConsumer.getId());
consumer = mImeSourceConsumer; consumer = mImeSourceConsumer;
consumer.setId(sourceId); consumer.setId(id);
} else { } else {
consumer = mConsumerCreator.apply(this, source); consumer = mConsumerCreator.apply(this, id, type);
} }
mSourceConsumers.put(sourceId, consumer); mSourceConsumers.put(id, consumer);
return consumer; return consumer;
} }
@@ -1663,8 +1663,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation
return mImeSourceConsumer; return mImeSourceConsumer;
} }
@VisibleForTesting void notifyVisibilityChanged() {
public void notifyVisibilityChanged() {
mHost.notifyInsetsChanged(); mHost.notifyInsetsChanged();
} }

View File

@@ -149,9 +149,12 @@ public class InsetsSourceConsumer {
// Check if we need to restore server visibility. // Check if we need to restore server visibility.
final InsetsSource localSource = mState.peekSource(mId); final InsetsSource localSource = mState.peekSource(mId);
final InsetsSource serverSource = mController.getLastDispatchedState().peekSource(mId); final InsetsSource serverSource = mController.getLastDispatchedState().peekSource(mId);
if (localSource != null && serverSource != null final boolean localVisible = localSource != null && localSource.isVisible();
&& localSource.isVisible() != serverSource.isVisible()) { final boolean serverVisible = serverSource != null && serverSource.isVisible();
localSource.setVisible(serverSource.isVisible()); if (localSource != null) {
localSource.setVisible(serverVisible);
}
if (localVisible != serverVisible) {
mController.notifyVisibilityChanged(); mController.notifyVisibilityChanged();
} }
} else { } else {

View File

@@ -131,10 +131,10 @@ public class InsetsControllerTest {
mTestClock = new OffsettableClock(); mTestClock = new OffsettableClock();
mTestHandler = new TestHandler(null, mTestClock); mTestHandler = new TestHandler(null, mTestClock);
mTestHost = spy(new TestHost(mViewRoot)); mTestHost = spy(new TestHost(mViewRoot));
mController = new InsetsController(mTestHost, (controller, source) -> { mController = new InsetsController(mTestHost, (controller, id, type) -> {
if (source.getType() == ime()) { if (type == ime()) {
return new InsetsSourceConsumer(source.getId(), source.getType(), return new InsetsSourceConsumer(id, type, controller.getState(),
controller.getState(), Transaction::new, controller) { Transaction::new, controller) {
private boolean mImeRequestedShow; private boolean mImeRequestedShow;
@@ -150,8 +150,8 @@ public class InsetsControllerTest {
} }
}; };
} else { } else {
return new InsetsSourceConsumer(source.getId(), source.getType(), return new InsetsSourceConsumer(id, type, controller.getState(),
controller.getState(), Transaction::new, controller); Transaction::new, controller);
} }
}, mTestHandler); }, mTestHandler);
final Rect rect = new Rect(5, 5, 5, 5); final Rect rect = new Rect(5, 5, 5, 5);
@@ -182,7 +182,8 @@ public class InsetsControllerTest {
@Test @Test
public void testControlsChanged() { public void testControlsChanged() {
mController.onControlsChanged(createSingletonControl(ID_STATUS_BAR, statusBars())); mController.onControlsChanged(createSingletonControl(ID_STATUS_BAR, statusBars()));
assertNotNull(mController.getSourceConsumer(mStatusSource).getControl().getLeash()); assertNotNull(
mController.getSourceConsumer(ID_STATUS_BAR, statusBars()).getControl().getLeash());
mController.addOnControllableInsetsChangedListener( mController.addOnControllableInsetsChangedListener(
((controller, typeMask) -> assertEquals(statusBars(), typeMask))); ((controller, typeMask) -> assertEquals(statusBars(), typeMask)));
} }
@@ -194,7 +195,7 @@ public class InsetsControllerTest {
mController.addOnControllableInsetsChangedListener(listener); mController.addOnControllableInsetsChangedListener(listener);
mController.onControlsChanged(createSingletonControl(ID_STATUS_BAR, statusBars())); mController.onControlsChanged(createSingletonControl(ID_STATUS_BAR, statusBars()));
mController.onControlsChanged(new InsetsSourceControl[0]); mController.onControlsChanged(new InsetsSourceControl[0]);
assertNull(mController.getSourceConsumer(mStatusSource).getControl()); assertNull(mController.getSourceConsumer(ID_STATUS_BAR, statusBars()).getControl());
InOrder inOrder = Mockito.inOrder(listener); InOrder inOrder = Mockito.inOrder(listener);
inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(0)); inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(0));
inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(statusBars())); inOrder.verify(listener).onControllableInsetsChanged(eq(mController), eq(statusBars()));
@@ -254,7 +255,7 @@ public class InsetsControllerTest {
// only the original thread that created view hierarchy can touch its views // only the original thread that created view hierarchy can touch its views
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.setSystemDrivenInsetsAnimationLoggingListener(loggingListener); mController.setSystemDrivenInsetsAnimationLoggingListener(loggingListener);
mController.getSourceConsumer(mImeSource).onWindowFocusGained(true); mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
// since there is no focused view, forcefully make IME visible. // since there is no focused view, forcefully make IME visible.
mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */); mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
// When using the animation thread, this must not invoke onReady() // When using the animation thread, this must not invoke onReady()
@@ -271,7 +272,7 @@ public class InsetsControllerTest {
prepareControls(); prepareControls();
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.getSourceConsumer(mImeSource).onWindowFocusGained(true); mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
// since there is no focused view, forcefully make IME visible. // since there is no focused view, forcefully make IME visible.
mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */); mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
mController.show(all()); mController.show(all());
@@ -284,7 +285,7 @@ public class InsetsControllerTest {
mController.hide(all()); mController.hide(all());
mController.cancelExistingAnimations(); mController.cancelExistingAnimations();
assertEquals(0, mController.getRequestedVisibleTypes() & types); assertEquals(0, mController.getRequestedVisibleTypes() & types);
mController.getSourceConsumer(mImeSource).onWindowFocusLost(); mController.getSourceConsumer(ID_IME, ime()).onWindowFocusLost();
}); });
InstrumentationRegistry.getInstrumentation().waitForIdleSync(); InstrumentationRegistry.getInstrumentation().waitForIdleSync();
} }
@@ -294,14 +295,14 @@ public class InsetsControllerTest {
InsetsSourceControl ime = createControl(ID_IME, ime()); InsetsSourceControl ime = createControl(ID_IME, ime());
mController.onControlsChanged(new InsetsSourceControl[] { ime }); mController.onControlsChanged(new InsetsSourceControl[] { ime });
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.getSourceConsumer(mImeSource).onWindowFocusGained(true); mController.getSourceConsumer(ID_IME, ime()).onWindowFocusGained(true);
mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */); mController.show(WindowInsets.Type.ime(), true /* fromIme */, null /* statsToken */);
mController.cancelExistingAnimations(); mController.cancelExistingAnimations();
assertTrue(isRequestedVisible(mController, ime())); assertTrue(isRequestedVisible(mController, ime()));
mController.hide(ime(), true /* fromIme */, null /* statsToken */); mController.hide(ime(), true /* fromIme */, null /* statsToken */);
mController.cancelExistingAnimations(); mController.cancelExistingAnimations();
assertFalse(isRequestedVisible(mController, ime())); assertFalse(isRequestedVisible(mController, ime()));
mController.getSourceConsumer(mImeSource).onWindowFocusLost(); mController.getSourceConsumer(ID_IME, ime()).onWindowFocusLost();
}); });
InstrumentationRegistry.getInstrumentation().waitForIdleSync(); InstrumentationRegistry.getInstrumentation().waitForIdleSync();
} }
@@ -914,7 +915,7 @@ public class InsetsControllerTest {
// Simulate IME insets is not controllable // Simulate IME insets is not controllable
mController.onControlsChanged(new InsetsSourceControl[0]); mController.onControlsChanged(new InsetsSourceControl[0]);
final InsetsSourceConsumer imeInsetsConsumer = final InsetsSourceConsumer imeInsetsConsumer =
mController.getSourceConsumer(mImeSource); mController.getSourceConsumer(ID_IME, ime());
assertNull(imeInsetsConsumer.getControl()); assertNull(imeInsetsConsumer.getControl());
// Verify IME requested visibility should be updated to IME consumer from controller. // Verify IME requested visibility should be updated to IME consumer from controller.

View File

@@ -219,10 +219,10 @@ public class InsetsSourceConsumerTest {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
InsetsState state = new InsetsState(); InsetsState state = new InsetsState();
ViewRootInsetsControllerHost host = new ViewRootInsetsControllerHost(mViewRoot); ViewRootInsetsControllerHost host = new ViewRootInsetsControllerHost(mViewRoot);
InsetsController insetsController = new InsetsController(host, (controller, source) -> { InsetsController insetsController = new InsetsController(host, (ic, id, type) -> {
if (source.getType() == ime()) { if (type == ime()) {
return new InsetsSourceConsumer(ID_IME, ime(), state, return new InsetsSourceConsumer(ID_IME, ime(), state,
() -> mMockTransaction, controller) { () -> mMockTransaction, ic) {
@Override @Override
public int requestShow(boolean fromController, public int requestShow(boolean fromController,
ImeTracker.Token statsToken) { ImeTracker.Token statsToken) {
@@ -230,11 +230,9 @@ public class InsetsSourceConsumerTest {
} }
}; };
} }
return new InsetsSourceConsumer(source.getId(), source.getType(), return new InsetsSourceConsumer(id, type, ic.getState(), Transaction::new, ic);
controller.getState(), Transaction::new, controller);
}, host.getHandler()); }, host.getHandler());
InsetsSource imeSource = new InsetsSource(ID_IME, ime()); InsetsSourceConsumer imeConsumer = insetsController.getSourceConsumer(ID_IME, ime());
InsetsSourceConsumer imeConsumer = insetsController.getSourceConsumer(imeSource);
// Initial IME insets source control with its leash. // Initial IME insets source control with its leash.
imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash, imeConsumer.setControl(new InsetsSourceControl(ID_IME, ime(), mLeash,