// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.omnibox.suggestions;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import androidx.core.view.WindowInsetsAnimationCompat;
import androidx.core.view.WindowInsetsCompat;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
import org.chromium.base.MathUtils;
import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.ui.InsetObserver;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.modelutil.PropertyModel;
import java.util.List;
/** Unit tests for {@link SuggestionsListAnimationDriver}. */
@RunWith(BaseRobolectricTestRunner.class)
public class SuggestionsListAnimationDriverTest {
private static final int VERTICAL_OFFSET = 20;
public @Rule MockitoRule mMockitoRule = MockitoJUnit.rule();
private SuggestionsListAnimationDriver mDriver;
private WindowInsetsAnimationCompat mImeAnimation;
private WindowInsetsAnimationCompat mNonImeAnimation;
private PropertyModel mListModel = new PropertyModel(SuggestionListProperties.ALL_KEYS);
@Mock private WindowAndroid mWindowAndroid;
@Mock InsetObserver mInsetObserver;
@Mock Runnable mShowRunnable;
private float mTranslation;
@Before
public void setUp() {
mTranslation = 0.0f;
when(mWindowAndroid.getInsetObserver()).thenReturn(mInsetObserver);
mImeAnimation = new WindowInsetsAnimationCompat(WindowInsetsCompat.Type.ime(), null, 160);
mNonImeAnimation =
new WindowInsetsAnimationCompat(WindowInsetsCompat.Type.statusBars(), null, 160);
mDriver =
new SuggestionsListAnimationDriver(
mWindowAndroid,
mListModel,
() -> mTranslation,
mShowRunnable,
VERTICAL_OFFSET);
}
@Test
public void testShowAnimation() {
mDriver.onOmniboxSessionStateChange(true);
assertEquals(mListModel.get(SuggestionListProperties.ALPHA), 0.0f, MathUtils.EPSILON);
verify(mInsetObserver).addWindowInsetsAnimationListener(mDriver);
verify(mShowRunnable, never()).run();
mDriver.onPrepare(mImeAnimation);
verify(mShowRunnable).run();
mImeAnimation.setFraction(0.4f);
mTranslation = 200.0f;
mDriver.onProgress(new WindowInsetsCompat.Builder().build(), List.of(mImeAnimation));
assertEquals(mListModel.get(SuggestionListProperties.ALPHA), 0.4f, MathUtils.EPSILON);
assertEquals(
mListModel.get(SuggestionListProperties.CHILD_TRANSLATION_Y),
200.0f + VERTICAL_OFFSET * 0.6f,
MathUtils.EPSILON);
mImeAnimation.setFraction(0.7f);
mTranslation = 100.0f;
mDriver.onProgress(new WindowInsetsCompat.Builder().build(), List.of(mImeAnimation));
assertEquals(mListModel.get(SuggestionListProperties.ALPHA), 0.7f, MathUtils.EPSILON);
assertEquals(
mListModel.get(SuggestionListProperties.CHILD_TRANSLATION_Y),
100.0f + VERTICAL_OFFSET * 0.3f,
MathUtils.EPSILON);
mTranslation = 0.0f;
mImeAnimation.setFraction(0.95f);
mDriver.onProgress(new WindowInsetsCompat.Builder().build(), List.of(mImeAnimation));
assertEquals(
mListModel.get(SuggestionListProperties.CHILD_TRANSLATION_Y),
VERTICAL_OFFSET * 0.05f,
MathUtils.EPSILON);
// Reported omnibox translation no longer matters once the animation is complete.
mTranslation = 10.0f;
mDriver.onEnd(mImeAnimation);
verify(mInsetObserver).removeWindowInsetsAnimationListener(mDriver);
assertEquals(mListModel.get(SuggestionListProperties.ALPHA), 1.0f, MathUtils.EPSILON);
assertEquals(
mListModel.get(SuggestionListProperties.CHILD_TRANSLATION_Y),
0.0f,
MathUtils.EPSILON);
mImeAnimation.setFraction(0.9f);
mDriver.onProgress(new WindowInsetsCompat.Builder().build(), List.of(mImeAnimation));
/// Progress updates after onEnd should be ignored.
assertEquals(mListModel.get(SuggestionListProperties.ALPHA), 1.0f, MathUtils.EPSILON);
assertEquals(
mListModel.get(SuggestionListProperties.CHILD_TRANSLATION_Y),
0.0f,
MathUtils.EPSILON);
}
@Test
public void testNonImeAnimation() {
mDriver.onOmniboxSessionStateChange(true);
assertEquals(mListModel.get(SuggestionListProperties.ALPHA), 0.0f, MathUtils.EPSILON);
mDriver.onPrepare(mNonImeAnimation);
verify(mShowRunnable, never()).run();
mNonImeAnimation.setFraction(0.2f);
mDriver.onProgress(new WindowInsetsCompat.Builder().build(), List.of(mNonImeAnimation));
assertEquals(mListModel.get(SuggestionListProperties.ALPHA), 0.0f, MathUtils.EPSILON);
mDriver.onPrepare(mImeAnimation);
mNonImeAnimation.setFraction(0.3f);
mImeAnimation.setFraction(0.1f);
mDriver.onProgress(
new WindowInsetsCompat.Builder().build(), List.of(mNonImeAnimation, mImeAnimation));
assertEquals(mListModel.get(SuggestionListProperties.ALPHA), 0.1f, MathUtils.EPSILON);
// Ending the non-ime animation should have no effect
mDriver.onEnd(mNonImeAnimation);
assertEquals(mListModel.get(SuggestionListProperties.ALPHA), 0.1f, MathUtils.EPSILON);
verify(mInsetObserver, never()).removeWindowInsetsAnimationListener(mDriver);
}
}