blob: e85ffb68de540daa39896527d5d20c9ddfe55a29 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.shade
import android.content.Context
import android.content.res.Resources
import android.content.res.XmlResourceParser
import android.graphics.Rect
import android.testing.AndroidTestingRunner
import android.view.DisplayCutout
import android.view.View
import android.view.WindowInsets
import android.widget.TextView
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.animation.ShadeInterpolation
import com.android.systemui.battery.BatteryMeterView
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.dump.DumpManager
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.qs.ChipVisibilityListener
import com.android.systemui.qs.HeaderPrivacyIconsController
import com.android.systemui.qs.carrier.QSCarrierGroup
import com.android.systemui.qs.carrier.QSCarrierGroupController
import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.HEADER_TRANSITION_ID
import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.LARGE_SCREEN_HEADER_CONSTRAINT
import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.LARGE_SCREEN_HEADER_TRANSITION_ID
import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.QQS_HEADER_CONSTRAINT
import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.QS_HEADER_CONSTRAINT
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.phone.StatusBarIconController
import com.android.systemui.statusbar.phone.StatusIconContainer
import com.android.systemui.statusbar.policy.FakeConfigurationController
import com.android.systemui.statusbar.policy.VariableDateView
import com.android.systemui.statusbar.policy.VariableDateViewController
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Answers
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
import org.mockito.Mock
import org.mockito.Mockito.anyBoolean
import org.mockito.Mockito.anyFloat
import org.mockito.Mockito.anyInt
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.inOrder
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
private val EMPTY_CHANGES = ConstraintsChanges()
/**
* Tests for [LargeScreenShadeHeaderController] when [Flags.COMBINED_QS_HEADERS] is `true`.
*
* Once that flag is removed, this class will be combined with
* [LargeScreenShadeHeaderControllerTest].
*/
@SmallTest
@RunWith(AndroidTestingRunner::class)
class LargeScreenShadeHeaderControllerCombinedTest : SysuiTestCase() {
@Mock
private lateinit var statusIcons: StatusIconContainer
@Mock
private lateinit var statusBarIconController: StatusBarIconController
@Mock
private lateinit var iconManagerFactory: StatusBarIconController.TintedIconManager.Factory
@Mock
private lateinit var iconManager: StatusBarIconController.TintedIconManager
@Mock
private lateinit var qsCarrierGroupController: QSCarrierGroupController
@Mock
private lateinit var qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder
@Mock
private lateinit var featureFlags: FeatureFlags
@Mock
private lateinit var clock: TextView
@Mock
private lateinit var date: VariableDateView
@Mock
private lateinit var carrierGroup: QSCarrierGroup
@Mock
private lateinit var batteryMeterView: BatteryMeterView
@Mock
private lateinit var batteryMeterViewController: BatteryMeterViewController
@Mock
private lateinit var privacyIconsController: HeaderPrivacyIconsController
@Mock
private lateinit var insetsProvider: StatusBarContentInsetsProvider
@Mock
private lateinit var variableDateViewControllerFactory: VariableDateViewController.Factory
@Mock
private lateinit var variableDateViewController: VariableDateViewController
@Mock
private lateinit var dumpManager: DumpManager
@Mock
private lateinit var combinedShadeHeadersConstraintManager:
CombinedShadeHeadersConstraintManager
@Mock
private lateinit var mockedContext: Context
@Mock(answer = Answers.RETURNS_MOCKS)
private lateinit var view: MotionLayout
@Mock
private lateinit var qqsConstraints: ConstraintSet
@Mock
private lateinit var qsConstraints: ConstraintSet
@Mock
private lateinit var largeScreenConstraints: ConstraintSet
@JvmField @Rule
val mockitoRule = MockitoJUnit.rule()
var viewVisibility = View.GONE
private lateinit var controller: LargeScreenShadeHeaderController
private lateinit var carrierIconSlots: List<String>
private val configurationController = FakeConfigurationController()
@Before
fun setUp() {
whenever<TextView>(view.findViewById(R.id.clock)).thenReturn(clock)
whenever(clock.context).thenReturn(mockedContext)
whenever<TextView>(view.findViewById(R.id.date)).thenReturn(date)
whenever(date.context).thenReturn(mockedContext)
whenever(variableDateViewControllerFactory.create(any()))
.thenReturn(variableDateViewController)
whenever<QSCarrierGroup>(view.findViewById(R.id.carrier_group)).thenReturn(carrierGroup)
whenever<BatteryMeterView>(view.findViewById(R.id.batteryRemainingIcon))
.thenReturn(batteryMeterView)
whenever<StatusIconContainer>(view.findViewById(R.id.statusIcons)).thenReturn(statusIcons)
whenever(statusIcons.context).thenReturn(context)
whenever(qsCarrierGroupControllerBuilder.setQSCarrierGroup(any()))
.thenReturn(qsCarrierGroupControllerBuilder)
whenever(qsCarrierGroupControllerBuilder.build()).thenReturn(qsCarrierGroupController)
whenever(view.context).thenReturn(context)
whenever(view.resources).thenReturn(context.resources)
whenever(view.setVisibility(ArgumentMatchers.anyInt())).then {
viewVisibility = it.arguments[0] as Int
null
}
whenever(view.visibility).thenAnswer { _ -> viewVisibility }
whenever(iconManagerFactory.create(any())).thenReturn(iconManager)
whenever(featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)).thenReturn(true)
whenever(featureFlags.isEnabled(Flags.NEW_HEADER)).thenReturn(true)
setUpDefaultInsets()
setUpMotionLayout(view)
controller = LargeScreenShadeHeaderController(
view,
statusBarIconController,
iconManagerFactory,
privacyIconsController,
insetsProvider,
configurationController,
variableDateViewControllerFactory,
batteryMeterViewController,
dumpManager,
featureFlags,
qsCarrierGroupControllerBuilder,
combinedShadeHeadersConstraintManager
)
whenever(view.isAttachedToWindow).thenReturn(true)
controller.init()
carrierIconSlots = listOf(
context.getString(com.android.internal.R.string.status_bar_mobile))
}
@Test
fun testCorrectConstraints() {
val captor = ArgumentCaptor.forClass(XmlResourceParser::class.java)
verify(qqsConstraints).load(eq(context), capture(captor))
assertThat(captor.value.getResId()).isEqualTo(R.xml.qqs_header)
verify(qsConstraints).load(eq(context), capture(captor))
assertThat(captor.value.getResId()).isEqualTo(R.xml.qs_header_new)
verify(largeScreenConstraints).load(eq(context), capture(captor))
assertThat(captor.value.getResId()).isEqualTo(R.xml.large_screen_shade_header)
}
@Test
fun testControllersCreatedAndInitialized() {
verify(variableDateViewController).init()
verify(batteryMeterViewController).init()
verify(batteryMeterViewController).ignoreTunerUpdates()
verify(batteryMeterView).setPercentShowMode(BatteryMeterView.MODE_ESTIMATE)
val inOrder = inOrder(qsCarrierGroupControllerBuilder)
inOrder.verify(qsCarrierGroupControllerBuilder).setQSCarrierGroup(carrierGroup)
inOrder.verify(qsCarrierGroupControllerBuilder).build()
}
@Test
fun testClockPivotLtr() {
val width = 200
whenever(clock.width).thenReturn(width)
whenever(clock.isLayoutRtl).thenReturn(false)
val captor = ArgumentCaptor.forClass(View.OnLayoutChangeListener::class.java)
verify(clock).addOnLayoutChangeListener(capture(captor))
captor.value.onLayoutChange(clock, 0, 1, 2, 3, 4, 5, 6, 7)
verify(clock).pivotX = 0f
}
@Test
fun testClockPivotRtl() {
val width = 200
whenever(clock.width).thenReturn(width)
whenever(clock.isLayoutRtl).thenReturn(true)
val captor = ArgumentCaptor.forClass(View.OnLayoutChangeListener::class.java)
verify(clock).addOnLayoutChangeListener(capture(captor))
captor.value.onLayoutChange(clock, 0, 1, 2, 3, 4, 5, 6, 7)
verify(clock).pivotX = width.toFloat()
}
@Test
fun testShadeExpanded_true() {
// When shade is expanded, view should be visible regardless of largeScreenActive
controller.largeScreenActive = false
controller.qsVisible = true
assertThat(viewVisibility).isEqualTo(View.VISIBLE)
controller.largeScreenActive = true
assertThat(viewVisibility).isEqualTo(View.VISIBLE)
}
@Test
fun testShadeExpanded_false() {
// When shade is not expanded, view should be invisible regardless of largeScreenActive
controller.largeScreenActive = false
controller.qsVisible = false
assertThat(viewVisibility).isEqualTo(View.INVISIBLE)
controller.largeScreenActive = true
assertThat(viewVisibility).isEqualTo(View.INVISIBLE)
}
@Test
fun testLargeScreenActive_true() {
controller.largeScreenActive = false // Make sure there's a change
clearInvocations(view)
controller.largeScreenActive = true
verify(view).setTransition(LARGE_SCREEN_HEADER_TRANSITION_ID)
}
@Test
fun testLargeScreenActive_false() {
controller.largeScreenActive = true // Make sure there's a change
clearInvocations(view)
controller.largeScreenActive = false
verify(view).setTransition(HEADER_TRANSITION_ID)
}
@Test
fun testShadeExpandedFraction() {
// View needs to be visible for this to actually take effect
controller.qsVisible = true
clearInvocations(view)
controller.shadeExpandedFraction = 0.3f
verify(view).alpha = ShadeInterpolation.getContentAlpha(0.3f)
clearInvocations(view)
controller.shadeExpandedFraction = 1f
verify(view).alpha = ShadeInterpolation.getContentAlpha(1f)
clearInvocations(view)
controller.shadeExpandedFraction = 0f
verify(view).alpha = ShadeInterpolation.getContentAlpha(0f)
}
@Test
fun testQsExpandedFraction_headerTransition() {
controller.qsVisible = true
controller.largeScreenActive = false
clearInvocations(view)
controller.qsExpandedFraction = 0.3f
verify(view).progress = 0.3f
}
@Test
fun testQsExpandedFraction_largeScreen() {
controller.qsVisible = true
controller.largeScreenActive = true
clearInvocations(view)
controller.qsExpandedFraction = 0.3f
verify(view, never()).progress = anyFloat()
}
@Test
fun testScrollY_headerTransition() {
controller.largeScreenActive = false
clearInvocations(view)
controller.qsScrollY = 20
verify(view).scrollY = 20
}
@Test
fun testScrollY_largeScreen() {
controller.largeScreenActive = true
clearInvocations(view)
controller.qsScrollY = 20
verify(view, never()).scrollY = anyInt()
}
@Test
fun testPrivacyChipVisibilityChanged_visible_changesCorrectConstraints() {
val chipVisibleChanges = createMockConstraintChanges()
val chipNotVisibleChanges = createMockConstraintChanges()
whenever(combinedShadeHeadersConstraintManager.privacyChipVisibilityConstraints(true))
.thenReturn(chipVisibleChanges)
whenever(combinedShadeHeadersConstraintManager.privacyChipVisibilityConstraints(false))
.thenReturn(chipNotVisibleChanges)
val captor = ArgumentCaptor.forClass(ChipVisibilityListener::class.java)
verify(privacyIconsController).chipVisibilityListener = capture(captor)
captor.value.onChipVisibilityRefreshed(true)
verify(chipVisibleChanges.qqsConstraintsChanges)!!.invoke(qqsConstraints)
verify(chipVisibleChanges.qsConstraintsChanges)!!.invoke(qsConstraints)
verify(chipVisibleChanges.largeScreenConstraintsChanges)!!.invoke(largeScreenConstraints)
verify(chipNotVisibleChanges.qqsConstraintsChanges, never())!!.invoke(any())
verify(chipNotVisibleChanges.qsConstraintsChanges, never())!!.invoke(any())
verify(chipNotVisibleChanges.largeScreenConstraintsChanges, never())!!.invoke(any())
}
@Test
fun testPrivacyChipVisibilityChanged_notVisible_changesCorrectConstraints() {
val chipVisibleChanges = createMockConstraintChanges()
val chipNotVisibleChanges = createMockConstraintChanges()
whenever(combinedShadeHeadersConstraintManager.privacyChipVisibilityConstraints(true))
.thenReturn(chipVisibleChanges)
whenever(combinedShadeHeadersConstraintManager.privacyChipVisibilityConstraints(false))
.thenReturn(chipNotVisibleChanges)
val captor = ArgumentCaptor.forClass(ChipVisibilityListener::class.java)
verify(privacyIconsController).chipVisibilityListener = capture(captor)
captor.value.onChipVisibilityRefreshed(false)
verify(chipVisibleChanges.qqsConstraintsChanges, never())!!.invoke(qqsConstraints)
verify(chipVisibleChanges.qsConstraintsChanges, never())!!.invoke(qsConstraints)
verify(chipVisibleChanges.largeScreenConstraintsChanges, never())!!
.invoke(largeScreenConstraints)
verify(chipNotVisibleChanges.qqsConstraintsChanges)!!.invoke(any())
verify(chipNotVisibleChanges.qsConstraintsChanges)!!.invoke(any())
verify(chipNotVisibleChanges.largeScreenConstraintsChanges)!!.invoke(any())
}
@Test
fun testInsetsGuides_ltr() {
whenever(view.isLayoutRtl).thenReturn(false)
val captor = ArgumentCaptor.forClass(View.OnApplyWindowInsetsListener::class.java)
verify(view).setOnApplyWindowInsetsListener(capture(captor))
val mockConstraintsChanges = createMockConstraintChanges()
val (insetLeft, insetRight) = 30 to 40
val (paddingStart, paddingEnd) = 10 to 20
whenever(view.paddingStart).thenReturn(paddingStart)
whenever(view.paddingEnd).thenReturn(paddingEnd)
mockInsetsProvider(insetLeft to insetRight, false)
whenever(combinedShadeHeadersConstraintManager
.edgesGuidelinesConstraints(anyInt(), anyInt(), anyInt(), anyInt())
).thenReturn(mockConstraintsChanges)
captor.value.onApplyWindowInsets(view, createWindowInsets())
verify(combinedShadeHeadersConstraintManager)
.edgesGuidelinesConstraints(insetLeft, paddingStart, insetRight, paddingEnd)
verify(mockConstraintsChanges.qqsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.qsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.largeScreenConstraintsChanges)!!.invoke(any())
}
@Test
fun testInsetsGuides_rtl() {
whenever(view.isLayoutRtl).thenReturn(true)
val captor = ArgumentCaptor.forClass(View.OnApplyWindowInsetsListener::class.java)
verify(view).setOnApplyWindowInsetsListener(capture(captor))
val mockConstraintsChanges = createMockConstraintChanges()
val (insetLeft, insetRight) = 30 to 40
val (paddingStart, paddingEnd) = 10 to 20
whenever(view.paddingStart).thenReturn(paddingStart)
whenever(view.paddingEnd).thenReturn(paddingEnd)
mockInsetsProvider(insetLeft to insetRight, false)
whenever(combinedShadeHeadersConstraintManager
.edgesGuidelinesConstraints(anyInt(), anyInt(), anyInt(), anyInt())
).thenReturn(mockConstraintsChanges)
captor.value.onApplyWindowInsets(view, createWindowInsets())
verify(combinedShadeHeadersConstraintManager)
.edgesGuidelinesConstraints(insetRight, paddingStart, insetLeft, paddingEnd)
verify(mockConstraintsChanges.qqsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.qsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.largeScreenConstraintsChanges)!!.invoke(any())
}
@Test
fun testNullCutout() {
val captor = ArgumentCaptor.forClass(View.OnApplyWindowInsetsListener::class.java)
verify(view).setOnApplyWindowInsetsListener(capture(captor))
val mockConstraintsChanges = createMockConstraintChanges()
whenever(combinedShadeHeadersConstraintManager.emptyCutoutConstraints())
.thenReturn(mockConstraintsChanges)
captor.value.onApplyWindowInsets(view, createWindowInsets(null))
verify(combinedShadeHeadersConstraintManager).emptyCutoutConstraints()
verify(combinedShadeHeadersConstraintManager, never())
.centerCutoutConstraints(anyBoolean(), anyInt())
verify(mockConstraintsChanges.qqsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.qsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.largeScreenConstraintsChanges)!!.invoke(any())
}
@Test
fun testEmptyCutout() {
val captor = ArgumentCaptor.forClass(View.OnApplyWindowInsetsListener::class.java)
verify(view).setOnApplyWindowInsetsListener(capture(captor))
val mockConstraintsChanges = createMockConstraintChanges()
whenever(combinedShadeHeadersConstraintManager.emptyCutoutConstraints())
.thenReturn(mockConstraintsChanges)
captor.value.onApplyWindowInsets(view, createWindowInsets())
verify(combinedShadeHeadersConstraintManager).emptyCutoutConstraints()
verify(combinedShadeHeadersConstraintManager, never())
.centerCutoutConstraints(anyBoolean(), anyInt())
verify(mockConstraintsChanges.qqsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.qsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.largeScreenConstraintsChanges)!!.invoke(any())
}
@Test
fun testCornerCutout_emptyRect() {
val captor = ArgumentCaptor.forClass(View.OnApplyWindowInsetsListener::class.java)
verify(view).setOnApplyWindowInsetsListener(capture(captor))
val mockConstraintsChanges = createMockConstraintChanges()
mockInsetsProvider(0 to 0, true)
whenever(combinedShadeHeadersConstraintManager.emptyCutoutConstraints())
.thenReturn(mockConstraintsChanges)
captor.value.onApplyWindowInsets(view, createWindowInsets())
verify(combinedShadeHeadersConstraintManager).emptyCutoutConstraints()
verify(combinedShadeHeadersConstraintManager, never())
.centerCutoutConstraints(anyBoolean(), anyInt())
verify(mockConstraintsChanges.qqsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.qsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.largeScreenConstraintsChanges)!!.invoke(any())
}
@Test
fun testCornerCutout_nonEmptyRect() {
val captor = ArgumentCaptor.forClass(View.OnApplyWindowInsetsListener::class.java)
verify(view).setOnApplyWindowInsetsListener(capture(captor))
val mockConstraintsChanges = createMockConstraintChanges()
mockInsetsProvider(0 to 0, true)
whenever(combinedShadeHeadersConstraintManager.emptyCutoutConstraints())
.thenReturn(mockConstraintsChanges)
captor.value.onApplyWindowInsets(view, createWindowInsets(Rect(1, 2, 3, 4)))
verify(combinedShadeHeadersConstraintManager).emptyCutoutConstraints()
verify(combinedShadeHeadersConstraintManager, never())
.centerCutoutConstraints(anyBoolean(), anyInt())
verify(mockConstraintsChanges.qqsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.qsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.largeScreenConstraintsChanges)!!.invoke(any())
}
@Test
fun testTopCutout_ltr() {
val width = 100
val paddingLeft = 10
val paddingRight = 20
val cutoutWidth = 30
whenever(view.isLayoutRtl).thenReturn(false)
whenever(view.width).thenReturn(width)
whenever(view.paddingLeft).thenReturn(paddingLeft)
whenever(view.paddingRight).thenReturn(paddingRight)
val captor = ArgumentCaptor.forClass(View.OnApplyWindowInsetsListener::class.java)
verify(view).setOnApplyWindowInsetsListener(capture(captor))
val mockConstraintsChanges = createMockConstraintChanges()
mockInsetsProvider(0 to 0, false)
whenever(combinedShadeHeadersConstraintManager
.centerCutoutConstraints(anyBoolean(), anyInt())
).thenReturn(mockConstraintsChanges)
captor.value.onApplyWindowInsets(view, createWindowInsets(Rect(0, 0, cutoutWidth, 1)))
verify(combinedShadeHeadersConstraintManager, never()).emptyCutoutConstraints()
val offset = (width - paddingLeft - paddingRight - cutoutWidth) / 2
verify(combinedShadeHeadersConstraintManager).centerCutoutConstraints(false, offset)
verify(mockConstraintsChanges.qqsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.qsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.largeScreenConstraintsChanges)!!.invoke(any())
}
@Test
fun testTopCutout_rtl() {
val width = 100
val paddingLeft = 10
val paddingRight = 20
val cutoutWidth = 30
whenever(view.isLayoutRtl).thenReturn(true)
whenever(view.width).thenReturn(width)
whenever(view.paddingLeft).thenReturn(paddingLeft)
whenever(view.paddingRight).thenReturn(paddingRight)
val captor = ArgumentCaptor.forClass(View.OnApplyWindowInsetsListener::class.java)
verify(view).setOnApplyWindowInsetsListener(capture(captor))
val mockConstraintsChanges = createMockConstraintChanges()
mockInsetsProvider(0 to 0, false)
whenever(combinedShadeHeadersConstraintManager
.centerCutoutConstraints(anyBoolean(), anyInt())
).thenReturn(mockConstraintsChanges)
captor.value.onApplyWindowInsets(view, createWindowInsets(Rect(0, 0, cutoutWidth, 1)))
verify(combinedShadeHeadersConstraintManager, never()).emptyCutoutConstraints()
val offset = (width - paddingLeft - paddingRight - cutoutWidth) / 2
verify(combinedShadeHeadersConstraintManager).centerCutoutConstraints(true, offset)
verify(mockConstraintsChanges.qqsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.qsConstraintsChanges)!!.invoke(any())
verify(mockConstraintsChanges.largeScreenConstraintsChanges)!!.invoke(any())
}
@Test
fun alarmIconNotIgnored() {
verify(statusIcons, never()).addIgnoredSlot(
context.getString(com.android.internal.R.string.status_bar_alarm_clock)
)
}
private fun createWindowInsets(
topCutout: Rect? = Rect()
): WindowInsets {
val windowInsets: WindowInsets = mock()
val displayCutout: DisplayCutout = mock()
whenever(windowInsets.displayCutout)
.thenReturn(if (topCutout != null) displayCutout else null)
whenever(displayCutout.boundingRectTop).thenReturn(topCutout)
return windowInsets
}
private fun mockInsetsProvider(
insets: Pair<Int, Int> = 0 to 0,
cornerCutout: Boolean = false,
) {
whenever(insetsProvider.getStatusBarContentInsetsForCurrentRotation())
.thenReturn(insets.toAndroidPair())
whenever(insetsProvider.currentRotationHasCornerCutout()).thenReturn(cornerCutout)
}
private fun createMockConstraintChanges(): ConstraintsChanges {
return ConstraintsChanges(mock(), mock(), mock())
}
private fun XmlResourceParser.getResId(): Int {
return Resources.getAttributeSetSourceResId(this)
}
private fun setUpMotionLayout(motionLayout: MotionLayout) {
whenever(motionLayout.getConstraintSet(QQS_HEADER_CONSTRAINT)).thenReturn(qqsConstraints)
whenever(motionLayout.getConstraintSet(QS_HEADER_CONSTRAINT)).thenReturn(qsConstraints)
whenever(motionLayout.getConstraintSet(LARGE_SCREEN_HEADER_CONSTRAINT))
.thenReturn(largeScreenConstraints)
}
private fun setUpDefaultInsets() {
whenever(combinedShadeHeadersConstraintManager
.edgesGuidelinesConstraints(anyInt(), anyInt(), anyInt(), anyInt())
).thenReturn(EMPTY_CHANGES)
whenever(combinedShadeHeadersConstraintManager.emptyCutoutConstraints())
.thenReturn(EMPTY_CHANGES)
whenever(combinedShadeHeadersConstraintManager
.centerCutoutConstraints(anyBoolean(), anyInt())
).thenReturn(EMPTY_CHANGES)
whenever(combinedShadeHeadersConstraintManager
.privacyChipVisibilityConstraints(anyBoolean())
).thenReturn(EMPTY_CHANGES)
whenever(insetsProvider.getStatusBarContentInsetsForCurrentRotation())
.thenReturn(Pair(0, 0).toAndroidPair())
whenever(insetsProvider.currentRotationHasCornerCutout()).thenReturn(false)
}
private fun<T, U> Pair<T, U>.toAndroidPair(): android.util.Pair<T, U> {
return android.util.Pair(first, second)
}
}