blob: 275dbfd516e446c3251e5f89a88af15cf79d1637 [file] [log] [blame]
package com.android.systemui.statusbar.notification.stack
import android.annotation.DimenRes
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.dump.DumpManager
import com.android.systemui.statusbar.EmptyShadeView
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
import com.android.systemui.statusbar.notification.row.ExpandableView
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.BypassController
import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.SectionProvider
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.mockito.Mockito.mock
import org.mockito.Mockito.`when` as whenever
@SmallTest
class StackScrollAlgorithmTest : SysuiTestCase() {
private val hostView = FrameLayout(context)
private val stackScrollAlgorithm = StackScrollAlgorithm(context, hostView)
private val expandableViewState = ExpandableViewState()
private val notificationRow = mock(ExpandableNotificationRow::class.java)
private val dumpManager = mock(DumpManager::class.java)
private val mStatusBarKeyguardViewManager = mock(StatusBarKeyguardViewManager::class.java)
private val ambientState = AmbientState(
context,
dumpManager,
SectionProvider { _, _ -> false },
BypassController { false },
mStatusBarKeyguardViewManager
)
private val testableResources = mContext.orCreateTestableResources
private fun px(@DimenRes id: Int): Float =
testableResources.resources.getDimensionPixelSize(id).toFloat()
private val bigGap = px(R.dimen.notification_section_divider_height)
private val smallGap = px(R.dimen.notification_section_divider_height_lockscreen)
@Before
fun setUp() {
whenever(notificationRow.viewState).thenReturn(expandableViewState)
hostView.addView(notificationRow)
}
@Test
fun resetViewStates_defaultHun_yTranslationIsInset() {
whenever(notificationRow.isPinned).thenReturn(true)
whenever(notificationRow.isHeadsUp).thenReturn(true)
stackScrollAlgorithm.resetViewStates(ambientState, 0)
assertThat(expandableViewState.yTranslation).isEqualTo(stackScrollAlgorithm.mHeadsUpInset)
}
@Test
fun resetViewStates_stackMargin_changesHunYTranslation() {
whenever(notificationRow.isPinned).thenReturn(true)
whenever(notificationRow.isHeadsUp).thenReturn(true)
val minHeadsUpTranslation = context.resources
.getDimensionPixelSize(R.dimen.notification_side_paddings)
// split shade case with top margin introduced by shade's status bar
ambientState.stackTopMargin = 100
stackScrollAlgorithm.resetViewStates(ambientState, 0)
// top margin presence should decrease heads up translation up to minHeadsUpTranslation
assertThat(expandableViewState.yTranslation).isEqualTo(minHeadsUpTranslation)
}
@Test
fun resetViewStates_emptyShadeView_isCenteredVertically() {
stackScrollAlgorithm.initView(context)
val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply {
layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100)
}
hostView.removeAllViews()
hostView.addView(emptyShadeView)
ambientState.layoutMaxHeight = 1280
stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
val marginBottom =
context.resources.getDimensionPixelSize(R.dimen.notification_panel_margin_bottom)
val fullHeight = ambientState.layoutMaxHeight + marginBottom - ambientState.stackY
val centeredY = ambientState.stackY + fullHeight / 2f - emptyShadeView.height / 2f
assertThat(emptyShadeView.viewState?.yTranslation).isEqualTo(centeredY)
}
@Test
fun getGapForLocation_onLockscreen_returnsSmallGap() {
val gap = stackScrollAlgorithm.getGapForLocation(
/* fractionToShade= */ 0f, /* onKeyguard= */ true)
assertThat(gap).isEqualTo(smallGap)
}
@Test
fun getGapForLocation_goingToShade_interpolatesGap() {
val gap = stackScrollAlgorithm.getGapForLocation(
/* fractionToShade= */ 0.5f, /* onKeyguard= */ true)
assertThat(gap).isEqualTo(smallGap * 0.5f + bigGap * 0.5f)
}
@Test
fun getGapForLocation_notOnLockscreen_returnsBigGap() {
val gap = stackScrollAlgorithm.getGapForLocation(
/* fractionToShade= */ 0f, /* onKeyguard= */ false)
assertThat(gap).isEqualTo(bigGap)
}
@Test
fun updateViewWithShelf_viewAboveShelf_viewShown() {
val viewStart = 0f
val shelfStart = 1f
val expandableView = mock(ExpandableView::class.java)
whenever(expandableView.isExpandAnimationRunning).thenReturn(false)
whenever(expandableView.hasExpandingChild()).thenReturn(false)
val expandableViewState = ExpandableViewState()
expandableViewState.yTranslation = viewStart
stackScrollAlgorithm.updateViewWithShelf(expandableView, expandableViewState, shelfStart)
assertFalse(expandableViewState.hidden)
}
@Test
fun updateViewWithShelf_viewBelowShelf_viewHidden() {
val shelfStart = 0f
val viewStart = 1f
val expandableView = mock(ExpandableView::class.java)
whenever(expandableView.isExpandAnimationRunning).thenReturn(false)
whenever(expandableView.hasExpandingChild()).thenReturn(false)
val expandableViewState = ExpandableViewState()
expandableViewState.yTranslation = viewStart
stackScrollAlgorithm.updateViewWithShelf(expandableView, expandableViewState, shelfStart)
assertTrue(expandableViewState.hidden)
}
@Test
fun updateViewWithShelf_viewBelowShelfButIsExpanding_viewShown() {
val shelfStart = 0f
val viewStart = 1f
val expandableView = mock(ExpandableView::class.java)
whenever(expandableView.isExpandAnimationRunning).thenReturn(true)
whenever(expandableView.hasExpandingChild()).thenReturn(true)
val expandableViewState = ExpandableViewState()
expandableViewState.yTranslation = viewStart
stackScrollAlgorithm.updateViewWithShelf(expandableView, expandableViewState, shelfStart)
assertFalse(expandableViewState.hidden)
}
}