Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit afda3796 authored by Cosmin Băieș's avatar Cosmin Băieș
Browse files

Add to pending controls in notifyControlRevoked

When the windowContainer of an InsetsSourceProvider is removed, it
will call onAnimationCancelled and then notifyControlRevoked. This
will remove the provider for the control target, before setting
mControlTarget to null in the provider itself, essentially notifying
the loss of control on the server side.

However, this does not guarantee that the update will always reach
the client, so the InsetsSourceConsumer might hold onto the stale
value. In some cases this can lead to an additional insets dispatch.

This adds the provider to the pending controls map in
notifyControlRevoked, following the same pattern as for updating
the previous control target in onControlTargetChanged. When
notifyPendingInsetsControlChanged is next called, it will add the
afterPrepareSurfacesRunnable. When this runnable starts, the
provider from the pending controls map will have a different control
target, as it was set to null in onAnimationCancelled, so it can
proceed with notifyInsetsControlChanged on the control target.

Flag: EXEMPT bugfix
Bug: 403662376
Test: atest InsetsStateControllerTest#testImeWindowRemoved_notifiesInsetsControlChanged
  WindowInsetsControllerTests#testImeInsetsFinalSizeIsMaximumSize
Change-Id: I5a78ef4c2b5b3e347ae4cc3501796b70d67397e6
parent bfe2c0c9
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -303,6 +303,8 @@ class InsetsStateController {
    void notifyControlRevoked(@NonNull InsetsControlTarget previousControlTarget,
            InsetsSourceProvider provider) {
        removeFromControlMaps(previousControlTarget, provider, false /* fake */);
        addToPendingControlMaps(previousControlTarget, provider);
        notifyPendingInsetsControlChanged();
    }

    private void onControlTargetChanged(InsetsSourceProvider provider,
+54 −0
Original line number Diff line number Diff line
@@ -363,6 +363,60 @@ public class InsetsStateControllerTest extends WindowTestsBase {
        assertNull(getController().getControlsForDispatch(app));
    }

    /**
     * Verifies that removing the IME window will notify the control target that it lost control
     * of the IME.
     */
    @Test
    public void testImeWindowRemoved_notifiesInsetsControlChanged() {
        final WindowState ime = newWindowBuilder("ime", TYPE_INPUT_METHOD).build();
        spyOn(ime);
        final WindowState app = createTestWindow("app");

        // Set app as IME control target
        final var imeInsetsProvider = getController().getOrCreateSourceProvider(ID_IME, ime());
        imeInsetsProvider.setWindowContainer(ime, null, null);
        getController().onImeControlTargetChanged(app);
        assertTrue("App has IME as pending control, is at is being set",
                getController().hasPendingControls(app));

        var controls = getController().getControlsForDispatch(app);
        assertNotNull("controlsForDispatch should be not null", controls);
        InsetsSourceControl imeControl = null;
        for (var control : controls) {
            if (control.getType() == ime()) {
                imeControl = control;
                break;
            }
        }
        assertNotNull("imeControl should be found", imeControl);

        // Dispatch gaining IME control to app.
        performSurfacePlacementAndWaitForWindowAnimator();
        assertFalse("App has no pending controls as adding IME was dispatched",
                getController().hasPendingControls(app));
        verify(app).notifyInsetsControlChanged(mDisplayContent.mDisplayId);

        // Reset invocation counter.
        clearInvocations(app);

        // Remove IME window, which will cancelAnimation. This will clear the control target of the
        // imeInsetsProvider, remove it from the control map, and add it to the pending control map.
        ime.removeImmediately();
        verify(ime).cancelAnimation();
        assertTrue("App has IME as pending control, as it is being removed",
                getController().hasPendingControls(app));
        assertNull("controlsForDispatch should be null",
                getController().getControlsForDispatch(app));

        // Dispatch losing IME control to app.
        performSurfacePlacementAndWaitForWindowAnimator();
        assertFalse("App has no pending controls as removing IME was dispatched",
                getController().hasPendingControls(app));

        verify(app).notifyInsetsControlChanged(mDisplayContent.mDisplayId);
    }

    @Test
    public void testControlTargetChangedWhileProviderHasNoWindow() {
        final WindowState app = newWindowBuilder("app", TYPE_APPLICATION).build();