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

Commit 20467a89 authored by Liran Binyamin's avatar Liran Binyamin Committed by Android (Google) Code Review
Browse files

Merge "Fix IME flicker when dismissing stack" into main

parents 3e864644 991328ef
Loading
Loading
Loading
Loading
+137 −1
Original line number Diff line number Diff line
@@ -49,7 +49,9 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit
@@ -174,6 +176,137 @@ class BubbleStackViewTest {
        assertThat(lastUpdate!!.expanded).isTrue()
    }

    @Test
    fun expandStack_imeHidden() {
        val bubble = createAndInflateBubble()

        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            bubbleStackView.addBubble(bubble)
        }

        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
        assertThat(bubbleStackView.bubbleCount).isEqualTo(1)

        positioner.setImeVisible(false, 0)

        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            // simulate a request from the bubble data listener to expand the stack
            bubbleStackView.isExpanded = true
            verify(sysuiProxy).onStackExpandChanged(true)
            shellExecutor.flushAll()
        }

        assertThat(bubbleStackViewManager.onImeHidden).isNull()
    }

    @Test
    fun collapseStack_imeHidden() {
        val bubble = createAndInflateBubble()

        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            bubbleStackView.addBubble(bubble)
        }

        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
        assertThat(bubbleStackView.bubbleCount).isEqualTo(1)

        positioner.setImeVisible(false, 0)

        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            // simulate a request from the bubble data listener to expand the stack
            bubbleStackView.isExpanded = true
            verify(sysuiProxy).onStackExpandChanged(true)
            shellExecutor.flushAll()
        }

        assertThat(bubbleStackViewManager.onImeHidden).isNull()

        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            // simulate a request from the bubble data listener to collapse the stack
            bubbleStackView.isExpanded = false
            verify(sysuiProxy).onStackExpandChanged(false)
            shellExecutor.flushAll()
        }

        assertThat(bubbleStackViewManager.onImeHidden).isNull()
    }

    @Test
    fun expandStack_waitsForIme() {
        val bubble = createAndInflateBubble()

        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            bubbleStackView.addBubble(bubble)
        }

        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
        assertThat(bubbleStackView.bubbleCount).isEqualTo(1)

        positioner.setImeVisible(true, 100)

        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            // simulate a request from the bubble data listener to expand the stack
            bubbleStackView.isExpanded = true
        }

        val onImeHidden = bubbleStackViewManager.onImeHidden
        assertThat(onImeHidden).isNotNull()
        verify(sysuiProxy, never()).onStackExpandChanged(any())
        positioner.setImeVisible(false, 0)
        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            onImeHidden!!.run()
            verify(sysuiProxy).onStackExpandChanged(true)
            shellExecutor.flushAll()
        }
    }

    @Test
    fun collapseStack_waitsForIme() {
        val bubble = createAndInflateBubble()

        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            bubbleStackView.addBubble(bubble)
        }

        InstrumentationRegistry.getInstrumentation().waitForIdleSync()
        assertThat(bubbleStackView.bubbleCount).isEqualTo(1)

        positioner.setImeVisible(true, 100)

        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            // simulate a request from the bubble data listener to expand the stack
            bubbleStackView.isExpanded = true
        }

        var onImeHidden = bubbleStackViewManager.onImeHidden
        assertThat(onImeHidden).isNotNull()
        verify(sysuiProxy, never()).onStackExpandChanged(any())
        positioner.setImeVisible(false, 0)
        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            onImeHidden!!.run()
            verify(sysuiProxy).onStackExpandChanged(true)
            shellExecutor.flushAll()
        }

        bubbleStackViewManager.onImeHidden = null
        positioner.setImeVisible(true, 100)

        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            // simulate a request from the bubble data listener to collapse the stack
            bubbleStackView.isExpanded = false
        }

        onImeHidden = bubbleStackViewManager.onImeHidden
        assertThat(onImeHidden).isNotNull()
        verify(sysuiProxy, never()).onStackExpandChanged(false)
        positioner.setImeVisible(false, 0)
        InstrumentationRegistry.getInstrumentation().runOnMainSync {
            onImeHidden!!.run()
            verify(sysuiProxy).onStackExpandChanged(false)
            shellExecutor.flushAll()
        }
    }

    @Test
    fun tapDifferentBubble_shouldReorder() {
        val bubble1 = createAndInflateChatBubble(key = "bubble1")
@@ -418,6 +551,7 @@ class BubbleStackViewTest {
    }

    private class FakeBubbleStackViewManager : BubbleStackViewManager {
        var onImeHidden: Runnable? = null

        override fun onAllBubblesAnimatedOut() {}

@@ -425,6 +559,8 @@ class BubbleStackViewTest {

        override fun checkNotificationPanelExpandedState(callback: Consumer<Boolean>) {}

        override fun hideCurrentInputMethod() {}
        override fun hideCurrentInputMethod(onImeHidden: Runnable?) {
            this.onImeHidden = onImeHidden
        }
    }
}
+9 −2
Original line number Diff line number Diff line
@@ -215,6 +215,8 @@ public class BubbleController implements ConfigurationChangeListener,
    private final BubblePositioner mBubblePositioner;
    private Bubbles.SysuiProxy mSysuiProxy;

    @Nullable private Runnable mOnImeHidden;

    // Tracks the id of the current (foreground) user.
    private int mCurrentUserId;
    // Current profiles of the user (e.g. user with a workprofile)
@@ -615,7 +617,8 @@ public class BubbleController implements ConfigurationChangeListener,
    /**
     * Hides the current input method, wherever it may be focused, via InputMethodManagerInternal.
     */
    void hideCurrentInputMethod() {
    void hideCurrentInputMethod(@Nullable Runnable onImeHidden) {
        mOnImeHidden = onImeHidden;
        mBubblePositioner.setImeVisible(false /* visible */, 0 /* height */);
        int displayId = mWindowManager.getDefaultDisplay().getDisplayId();
        try {
@@ -2267,7 +2270,7 @@ public class BubbleController implements ConfigurationChangeListener,
        if (mLayerView != null && mLayerView.isExpanded()) {
            if (mBubblePositioner.isImeVisible()) {
                // If we're collapsing, hide the IME
                hideCurrentInputMethod();
                hideCurrentInputMethod(null);
            }
            mLayerView.collapse();
        }
@@ -2552,6 +2555,10 @@ public class BubbleController implements ConfigurationChangeListener,
            mBubblePositioner.setImeVisible(imeVisible, totalImeHeight);
            if (mStackView != null) {
                mStackView.setImeVisible(imeVisible);
                if (!imeVisible && mOnImeHidden != null) {
                    mOnImeHidden.run();
                    mOnImeHidden = null;
                }
            }
        }

+1 −1
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ interface BubbleExpandedViewManager {
                override fun isShowingAsBubbleBar(): Boolean = controller.isShowingAsBubbleBar

                override fun hideCurrentInputMethod() {
                    controller.hideCurrentInputMethod()
                    controller.hideCurrentInputMethod(null)
                }

                override fun updateBubbleBarLocation(
+42 −21
Original line number Diff line number Diff line
@@ -2233,19 +2233,22 @@ public class BubbleStackView extends FrameLayout

        boolean wasExpanded = mIsExpanded;

        hideCurrentInputMethod();

        // Do the actual expansion/collapse after the IME is hidden if it's currently visible in
        // order to avoid flickers
        Runnable onImeHidden = () -> {
            mSysuiProxyProvider.getSysuiProxy().onStackExpandChanged(shouldExpand);

            if (wasExpanded) {
                stopMonitoringSwipeUpGesture();
                animateCollapse();
                showManageMenu(false);
            logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
                logBubbleEvent(mExpandedBubble,
                        FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
            } else {
                animateExpansion();
                // TODO: move next line to BubbleData
            logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
                logBubbleEvent(mExpandedBubble,
                        FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
                logBubbleEvent(mExpandedBubble,
                        FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED);
                mManager.checkNotificationPanelExpandedState(notifPanelExpanded -> {
@@ -2256,6 +2259,14 @@ public class BubbleStackView extends FrameLayout
            }
            notifyExpansionChanged(mExpandedBubble, mIsExpanded);
            announceExpandForAccessibility(mExpandedBubble, mIsExpanded);
        };

        if (mPositioner.isImeVisible()) {
            hideCurrentInputMethod(onImeHidden);
        } else {
            // the IME is already hidden, so run the runnable immediately
            onImeHidden.run();
        }
    }

    /**
@@ -2373,7 +2384,17 @@ public class BubbleStackView extends FrameLayout
     * not.
     */
    void hideCurrentInputMethod() {
        mManager.hideCurrentInputMethod();
        mManager.hideCurrentInputMethod(null);
    }

    /**
     * Hides the IME similar to {@link #hideCurrentInputMethod()} but also runs {@code onImeHidden}
     * after after the IME is hidden.
     *
     * @see #hideCurrentInputMethod()
     */
    void hideCurrentInputMethod(Runnable onImeHidden) {
        mManager.hideCurrentInputMethod(onImeHidden);
    }

    /** Set the stack position to whatever the positioner says. */
+3 −3
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ interface BubbleStackViewManager {
    fun checkNotificationPanelExpandedState(callback: Consumer<Boolean>)

    /** Requests to hide the current input method. */
    fun hideCurrentInputMethod()
    fun hideCurrentInputMethod(onImeHidden: Runnable?)

    companion object {

@@ -52,8 +52,8 @@ interface BubbleStackViewManager {
                controller.isNotificationPanelExpanded(callback)
            }

            override fun hideCurrentInputMethod() {
                controller.hideCurrentInputMethod()
            override fun hideCurrentInputMethod(onImeHidden: Runnable?) {
                controller.hideCurrentInputMethod(onImeHidden)
            }
        }
    }