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

Commit 117c5a00 authored by Chris Göllner's avatar Chris Göllner
Browse files

Prepare SystemEventChipAnimationController for multi display

- Separate interface and impl
- Turn it into an @AssistedInject class

Test: Build & Run
Test: SystemEventChipAnimationControllerTest
Flag: EXEMPT no behavior change
Bug: 362720432
Change-Id: Ic6e3179a19ccdf712c53e3a71633028a6ee8aa61
parent 7a44ee9b
Loading
Loading
Loading
Loading
+6 −12
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@ import com.android.systemui.animation.AnimatorTestRule
import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.capture
@@ -50,11 +49,10 @@ import org.mockito.MockitoAnnotations
@RunWith(AndroidJUnit4::class)
@TestableLooper.RunWithLooper
class SystemEventChipAnimationControllerTest : SysuiTestCase() {
    private lateinit var controller: SystemEventChipAnimationController
    private lateinit var controller: SystemEventChipAnimationControllerImpl

    @get:Rule val animatorTestRule = AnimatorTestRule(this)
    @Mock private lateinit var sbWindowController: StatusBarWindowController
    @Mock private lateinit var sbWindowControllerStore: StatusBarWindowControllerStore
    @Mock private lateinit var insetsProvider: StatusBarContentInsetsProvider

    private var testView = TestView(mContext)
@@ -63,7 +61,6 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() {
    @Before
    fun setup() {
        MockitoAnnotations.initMocks(this)
        whenever(sbWindowControllerStore.defaultDisplay).thenReturn(sbWindowController)
        // StatusBarWindowController is mocked. The addViewToWindow function needs to be mocked to
        // ensure that the chip view is added to a parent view
        whenever(sbWindowController.addViewToWindow(any(), any())).then {
@@ -76,7 +73,7 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() {
            )
            statusbarFake.addView(
                it.arguments[0] as View,
                it.arguments[1] as FrameLayout.LayoutParams
                it.arguments[1] as FrameLayout.LayoutParams,
            )
        }

@@ -86,16 +83,16 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() {
                    /* left= */ insets,
                    /* top= */ insets,
                    /* right= */ insets,
                    /* bottom= */ 0
                    /* bottom= */ 0,
                )
            )
        whenever(insetsProvider.getStatusBarContentAreaForCurrentRotation())
            .thenReturn(portraitArea)

        controller =
            SystemEventChipAnimationController(
            SystemEventChipAnimationControllerImpl(
                context = mContext,
                statusBarWindowControllerStore = sbWindowControllerStore,
                statusBarWindowController = sbWindowController,
                contentInsetsProvider = insetsProvider,
            )
    }
@@ -156,10 +153,7 @@ class SystemEventChipAnimationControllerTest : SysuiTestCase() {
            val lp = it.arguments[1] as FrameLayout.LayoutParams
            assertThat(lp.gravity and Gravity.VERTICAL_GRAVITY_MASK).isEqualTo(Gravity.TOP)

            statusbarFake.addView(
                it.arguments[0] as View,
                lp,
            )
            statusbarFake.addView(it.arguments[0] as View, lp)
        }

        // GIVEN insets provider gives the correct content area
+2 −2
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ import dagger.Binds
import dagger.Module
import dagger.Provides

@Module
@Module(includes = [SystemEventChipAnimationControllerModule::class])
interface StatusBarEventsModule {

    companion object {
+63 −16
Original line number Diff line number Diff line
@@ -31,22 +31,46 @@ import androidx.core.animation.AnimatorListenerAdapter
import androidx.core.animation.AnimatorSet
import androidx.core.animation.ValueAnimator
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.res.R
import com.android.systemui.statusbar.phone.StatusBarContentInsetsChangedListener
import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
import com.android.systemui.statusbar.window.StatusBarWindowController
import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
import com.android.systemui.util.animation.AnimationUtil.Companion.frames
import javax.inject.Inject
import dagger.Module
import dagger.Provides
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlin.math.roundToInt

/** Controls the view for system event animations. */
class SystemEventChipAnimationController
@Inject
interface SystemEventChipAnimationController : SystemStatusAnimationCallback {

    /**
     * Give the chip controller a chance to inflate and configure the chip view before we start
     * animating
     */
    fun prepareChipAnimation(viewCreator: ViewCreator)

    fun init()

    /** Announces [contentDescriptions] for accessibility. */
    fun announceForAccessibility(contentDescriptions: String)

    override fun onSystemEventAnimationBegin(): Animator

    override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator
}

class SystemEventChipAnimationControllerImpl
@AssistedInject
constructor(
    private val context: Context,
    private val statusBarWindowControllerStore: StatusBarWindowControllerStore,
    private val contentInsetsProvider: StatusBarContentInsetsProvider,
) : SystemStatusAnimationCallback {
    @Assisted private val context: Context,
    @Assisted private val statusBarWindowController: StatusBarWindowController,
    @Assisted private val contentInsetsProvider: StatusBarContentInsetsProvider,
) : SystemEventChipAnimationController {

    private lateinit var animationWindowView: FrameLayout
    private lateinit var themedContext: ContextThemeWrapper
@@ -77,11 +101,7 @@ constructor(
    // TODO: move to dagger
    @VisibleForTesting var initialized = false

    /**
     * Give the chip controller a chance to inflate and configure the chip view before we start
     * animating
     */
    fun prepareChipAnimation(viewCreator: ViewCreator) {
    override fun prepareChipAnimation(viewCreator: ViewCreator) {
        if (!initialized) {
            init()
        }
@@ -266,7 +286,7 @@ constructor(
        return animSet
    }

    fun init() {
    override fun init() {
        initialized = true
        themedContext = ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings)
        animationWindowView =
@@ -276,7 +296,7 @@ constructor(
        val height = themedContext.resources.getDimensionPixelSize(R.dimen.status_bar_height)
        val lp = FrameLayout.LayoutParams(MATCH_PARENT, height)
        lp.gravity = Gravity.END or Gravity.TOP
        statusBarWindowControllerStore.defaultDisplay.addViewToWindow(animationWindowView, lp)
        statusBarWindowController.addViewToWindow(animationWindowView, lp)
        animationWindowView.clipToPadding = false
        animationWindowView.clipChildren = false

@@ -306,8 +326,7 @@ constructor(
        )
    }

    /** Announces [contentDescriptions] for accessibility. */
    fun announceForAccessibility(contentDescriptions: String) {
    override fun announceForAccessibility(contentDescriptions: String) {
        currentAnimatedView?.view?.announceForAccessibility(contentDescriptions)
    }

@@ -396,6 +415,15 @@ constructor(
            animRect.bottom,
        )
    }

    @AssistedFactory
    interface Factory {
        fun create(
            context: Context,
            statusBarWindowController: StatusBarWindowController,
            contentInsetsProvider: StatusBarContentInsetsProvider,
        ): SystemEventChipAnimationControllerImpl
    }
}

/** Chips should provide a view that can be animated with something better than a fade-in */
@@ -415,3 +443,22 @@ interface BackgroundAnimatableView {
// Animation directions
private const val LEFT = 1
private const val RIGHT = 2

@Module
object SystemEventChipAnimationControllerModule {

    @Provides
    @SysUISingleton
    fun controller(
        factory: SystemEventChipAnimationControllerImpl.Factory,
        context: Context,
        statusBarWindowControllerStore: StatusBarWindowControllerStore,
        contentInsetsProvider: StatusBarContentInsetsProvider,
    ): SystemEventChipAnimationController {
        return factory.create(
            context,
            statusBarWindowControllerStore.defaultDisplay,
            contentInsetsProvider,
        )
    }
}
+12 −16
Original line number Diff line number Diff line
@@ -88,21 +88,17 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() {
            .thenReturn(statusBarWindowController)
        systemClock = FakeSystemClock()
        chipAnimationController =
            SystemEventChipAnimationController(
            SystemEventChipAnimationControllerImpl(
                mContext,
                statusBarWindowControllerStore,
                statusBarWindowController,
                statusBarContentInsetProvider,
            )

        // StatusBarContentInsetProvider is mocked. Ensure that it returns some mocked values.
        whenever(statusBarContentInsetProvider.getStatusBarContentInsetsForCurrentRotation())
            .thenReturn(
                Insets.of(/* left = */ 10, /* top = */ 10, /* right = */ 10, /* bottom = */ 0)
            )
            .thenReturn(Insets.of(/* left= */ 10, /* top= */ 10, /* right= */ 10, /* bottom= */ 0))
        whenever(statusBarContentInsetProvider.getStatusBarContentAreaForCurrentRotation())
            .thenReturn(
                Rect(/* left = */ 10, /* top = */ 10, /* right = */ 990, /* bottom = */ 100)
            )
            .thenReturn(Rect(/* left= */ 10, /* top= */ 10, /* right= */ 990, /* bottom= */ 100))

        // StatusBarWindowController is mocked. The addViewToWindow function needs to be mocked to
        // ensure that the chip view is added to a parent view
@@ -111,7 +107,7 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() {
            statusbarFake.layout(/* l= */ 0, /* t= */ 0, /* r= */ 1000, /* b= */ 100)
            statusbarFake.addView(
                it.arguments[0] as View,
                it.arguments[1] as FrameLayout.LayoutParams
                it.arguments[1] as FrameLayout.LayoutParams,
            )
        }
    }
@@ -386,7 +382,7 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() {
        scheduleFakeEventWithView(
            accessibilityDesc,
            mockAnimatableView,
            shouldAnnounceAccessibilityEvent = true
            shouldAnnounceAccessibilityEvent = true,
        )
        fastForwardAnimationToState(ANIMATING_OUT)

@@ -405,7 +401,7 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() {
        scheduleFakeEventWithView(
            accessibilityDesc,
            mockAnimatableView,
            shouldAnnounceAccessibilityEvent = true
            shouldAnnounceAccessibilityEvent = true,
        )
        fastForwardAnimationToState(ANIMATING_OUT)

@@ -424,7 +420,7 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() {
        scheduleFakeEventWithView(
            accessibilityDesc,
            mockAnimatableView,
            shouldAnnounceAccessibilityEvent = false
            shouldAnnounceAccessibilityEvent = false,
        )
        fastForwardAnimationToState(ANIMATING_OUT)

@@ -637,13 +633,13 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() {
    private fun scheduleFakeEventWithView(
        desc: String?,
        view: BackgroundAnimatableView,
        shouldAnnounceAccessibilityEvent: Boolean
        shouldAnnounceAccessibilityEvent: Boolean,
    ) {
        val fakeEvent =
            FakeStatusEvent(
                viewCreator = { view },
                contentDescription = desc,
                shouldAnnounceAccessibilityEvent = shouldAnnounceAccessibilityEvent
                shouldAnnounceAccessibilityEvent = shouldAnnounceAccessibilityEvent,
            )
        systemStatusAnimationScheduler.onStatusEvent(fakeEvent)
    }
@@ -668,7 +664,7 @@ class SystemStatusAnimationSchedulerImplTest : SysuiTestCase() {
                dumpManager,
                systemClock,
                CoroutineScope(StandardTestDispatcher(testScope.testScheduler)),
                logger
                logger,
            )
        // add a mock listener
        systemStatusAnimationScheduler.addCallback(listener)