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

Commit 84d048dd authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[flexiglass] Adds CUI markers for AOD" into main

parents 9278bafb f4b4cd27
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.scene

import android.view.View
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.KeyguardViewConfigurator
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
@@ -62,12 +63,14 @@ interface LockscreenSceneModule {
            notificationScrimViewModelFactory: NotificationLockscreenScrimViewModel.Factory,
            blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>,
            clockInteractor: KeyguardClockInteractor,
            interactionJankMonitor: InteractionJankMonitor,
        ): LockscreenContent {
            return LockscreenContent(
                viewModelFactory,
                notificationScrimViewModelFactory,
                blueprints,
                clockInteractor,
                interactionJankMonitor,
            )
        }
    }
+41 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.keyguard.ui.composable

import android.view.View
import androidx.compose.foundation.layout.Box
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
@@ -25,8 +26,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentScope
import com.android.internal.jank.Cuj
import com.android.internal.jank.Cuj.CujType
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.compose.modifiers.sysuiResTag
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.transition.KeyguardTransitionAnimationCallback
import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.lifecycle.rememberViewModel
@@ -44,6 +50,7 @@ class LockscreenContent(
    private val notificationScrimViewModelFactory: NotificationLockscreenScrimViewModel.Factory,
    private val blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>,
    private val clockInteractor: KeyguardClockInteractor,
    private val interactionJankMonitor: InteractionJankMonitor,
) {
    private val blueprintByBlueprintId: Map<String, ComposableLockscreenSceneBlueprint> by lazy {
        blueprints.associateBy { it.id }
@@ -51,8 +58,14 @@ class LockscreenContent(

    @Composable
    fun ContentScope.Content(modifier: Modifier = Modifier) {
        val view = LocalView.current
        val viewModel =
            rememberViewModel("LockscreenContent-viewModel") { viewModelFactory.create() }
            rememberViewModel("LockscreenContent-viewModel") {
                viewModelFactory.create(
                    keyguardTransitionAnimationCallback =
                        KeyguardTransitionAnimationCallbackImpl(view, interactionJankMonitor)
                )
            }
        val notificationLockscreenScrimViewModel =
            rememberViewModel("LockscreenContent-scrimViewModel") {
                notificationScrimViewModelFactory.create()
@@ -69,7 +82,6 @@ class LockscreenContent(

        val coroutineScope = rememberCoroutineScope()
        val blueprintId by viewModel.blueprintId(coroutineScope).collectAsStateWithLifecycle()
        val view = LocalView.current
        DisposableEffect(view) {
            clockInteractor.clockEventController.registerListeners(view)

@@ -83,3 +95,30 @@ class LockscreenContent(
        }
    }
}

private class KeyguardTransitionAnimationCallbackImpl(
    private val view: View,
    private val interactionJankMonitor: InteractionJankMonitor,
) : KeyguardTransitionAnimationCallback {

    override fun onAnimationStarted(from: KeyguardState, to: KeyguardState) {
        cujOrNull(from, to)?.let { cuj -> interactionJankMonitor.begin(view, cuj) }
    }

    override fun onAnimationEnded(from: KeyguardState, to: KeyguardState) {
        cujOrNull(from, to)?.let { cuj -> interactionJankMonitor.end(cuj) }
    }

    override fun onAnimationCanceled(from: KeyguardState, to: KeyguardState) {
        cujOrNull(from, to)?.let { cuj -> interactionJankMonitor.cancel(cuj) }
    }

    @CujType
    private fun cujOrNull(from: KeyguardState, to: KeyguardState): Int? {
        return when {
            from == KeyguardState.AOD -> Cuj.CUJ_LOCKSCREEN_TRANSITION_FROM_AOD
            to == KeyguardState.AOD -> Cuj.CUJ_LOCKSCREEN_TRANSITION_TO_AOD
            else -> null
        }
    }
}
+97 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.keyguard.shared.transition

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class FakeKeyguardTransitionAnimationCallbackTest : SysuiTestCase() {

    private val kosmos = testKosmos().useUnconfinedTestDispatcher()

    val underTest = FakeKeyguardTransitionAnimationCallback()

    @Test
    fun onAnimationStarted() =
        kosmos.runTest {
            assertThat(underTest.activeAnimations).isEmpty()

            underTest.onAnimationStarted(KeyguardState.LOCKSCREEN, KeyguardState.AOD)
            assertThat(underTest.activeAnimations).hasSize(1)

            underTest.onAnimationStarted(KeyguardState.AOD, KeyguardState.ALTERNATE_BOUNCER)
            assertThat(underTest.activeAnimations).hasSize(2)
        }

    @Test
    fun onAnimationEnded() =
        kosmos.runTest {
            underTest.onAnimationStarted(KeyguardState.LOCKSCREEN, KeyguardState.AOD)
            underTest.onAnimationStarted(KeyguardState.AOD, KeyguardState.ALTERNATE_BOUNCER)
            assertThat(underTest.activeAnimations).hasSize(2)

            underTest.onAnimationEnded(KeyguardState.AOD, KeyguardState.ALTERNATE_BOUNCER)
            assertThat(underTest.activeAnimations).hasSize(1)

            underTest.onAnimationEnded(KeyguardState.LOCKSCREEN, KeyguardState.AOD)
            assertThat(underTest.activeAnimations).isEmpty()
        }

    @Test
    fun onAnimationCanceled() =
        kosmos.runTest {
            underTest.onAnimationStarted(KeyguardState.LOCKSCREEN, KeyguardState.AOD)
            underTest.onAnimationStarted(KeyguardState.AOD, KeyguardState.ALTERNATE_BOUNCER)
            assertThat(underTest.activeAnimations).hasSize(2)

            underTest.onAnimationCanceled(KeyguardState.AOD, KeyguardState.ALTERNATE_BOUNCER)
            assertThat(underTest.activeAnimations).hasSize(1)

            underTest.onAnimationCanceled(KeyguardState.LOCKSCREEN, KeyguardState.AOD)
            assertThat(underTest.activeAnimations).isEmpty()
        }

    @Test(expected = IllegalStateException::class)
    fun onAnimationEnded_throwsWhenNoSuchAnimation() =
        kosmos.runTest {
            underTest.onAnimationStarted(KeyguardState.LOCKSCREEN, KeyguardState.AOD)
            underTest.onAnimationStarted(KeyguardState.AOD, KeyguardState.ALTERNATE_BOUNCER)
            assertThat(underTest.activeAnimations).hasSize(2)

            underTest.onAnimationEnded(KeyguardState.AOD, KeyguardState.LOCKSCREEN)
        }

    @Test(expected = IllegalStateException::class)
    fun onAnimationCanceled_throwsWhenNoSuchAnimation() =
        kosmos.runTest {
            underTest.onAnimationStarted(KeyguardState.LOCKSCREEN, KeyguardState.AOD)
            underTest.onAnimationStarted(KeyguardState.AOD, KeyguardState.ALTERNATE_BOUNCER)
            assertThat(underTest.activeAnimations).hasSize(2)

            underTest.onAnimationCanceled(KeyguardState.AOD, KeyguardState.LOCKSCREEN)
        }
}
+138 −152
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.authController
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.DisableSceneContainer
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.keyguard.data.repository.fakeKeyguardClockRepository
@@ -29,7 +28,12 @@ import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepos
import com.android.systemui.keyguard.data.repository.keyguardOcclusionRepository
import com.android.systemui.keyguard.shared.model.ClockSize
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.transition.fakeKeyguardTransitionAnimationCallback
import com.android.systemui.keyguard.shared.transition.keyguardTransitionAnimationCallbackDelegator
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.lifecycle.activateIn
import com.android.systemui.res.R
@@ -42,8 +46,7 @@ import com.android.systemui.unfold.fakeUnfoldTransitionProgressProvider
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import java.util.Locale
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.Job
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -56,7 +59,8 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa

    private val kosmos: Kosmos = testKosmos()

    lateinit var underTest: LockscreenContentViewModel
    private lateinit var underTest: LockscreenContentViewModel
    private val activationJob = Job()

    companion object {
        @JvmStatic
@@ -74,67 +78,57 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
    fun setup() {
        with(kosmos) {
            shadeRepository.setShadeLayoutWide(false)
            underTest = lockscreenContentViewModel
            underTest.activateIn(testScope)
            underTest =
                lockscreenContentViewModelFactory.create(fakeKeyguardTransitionAnimationCallback)
            underTest.activateIn(testScope, activationJob)
        }
    }

    @Test
    fun isUdfpsVisible_withUdfps_true() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            whenever(authController.isUdfpsSupported).thenReturn(true)
            assertThat(underTest.isUdfpsVisible).isTrue()
        }
        }

    @Test
    fun isUdfpsVisible_withoutUdfps_false() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            whenever(authController.isUdfpsSupported).thenReturn(false)
            assertThat(underTest.isUdfpsVisible).isFalse()
        }
        }

    @Test
    @DisableSceneContainer
    fun clockSize_withLargeClock_true() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val clockSize by collectLastValue(underTest.clockSize)
            fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
            assertThat(clockSize).isEqualTo(ClockSize.LARGE)
        }
        }

    @Test
    @DisableSceneContainer
    fun clockSize_withSmallClock_false() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val clockSize by collectLastValue(underTest.clockSize)
            fakeKeyguardClockRepository.setClockSize(ClockSize.SMALL)
            assertThat(clockSize).isEqualTo(ClockSize.SMALL)
        }
        }

    @Test
    fun areNotificationsVisible_splitShadeTrue_true() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
            shadeRepository.setShadeLayoutWide(true)
            fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)

            assertThat(areNotificationsVisible).isTrue()
        }
        }

    @Test
    fun areNotificationsVisible_dualShadeWideOnLockscreen_true() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
            kosmos.enableDualShade()
            shadeRepository.setShadeLayoutWide(true)
@@ -142,56 +136,46 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa

            assertThat(areNotificationsVisible).isTrue()
        }
        }

    @Test
    @DisableSceneContainer
    fun areNotificationsVisible_withSmallClock_true() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
            fakeKeyguardClockRepository.setClockSize(ClockSize.SMALL)
            assertThat(areNotificationsVisible).isTrue()
        }
        }

    @Test
    @DisableSceneContainer
    fun areNotificationsVisible_withLargeClock_false() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val areNotificationsVisible by collectLastValue(underTest.areNotificationsVisible())
            fakeKeyguardClockRepository.setClockSize(ClockSize.LARGE)
            assertThat(areNotificationsVisible).isFalse()
        }
        }

    @Test
    fun isShadeLayoutWide_withConfigTrue_true() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
            shadeRepository.setShadeLayoutWide(true)

            assertThat(isShadeLayoutWide).isTrue()
        }
        }

    @Test
    fun isShadeLayoutWide_withConfigFalse_false() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val isShadeLayoutWide by collectLastValue(underTest.isShadeLayoutWide)
            shadeRepository.setShadeLayoutWide(false)

            assertThat(isShadeLayoutWide).isFalse()
        }
        }

    @Test
    fun unfoldTranslations() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val maxTranslation = prepareConfiguration()
            val translations by collectLastValue(underTest.unfoldTranslations)

@@ -203,10 +187,8 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
            repeat(10) { repetition ->
                val transitionProgress = 0.1f * (repetition + 1)
                unfoldProvider.onTransitionProgress(transitionProgress)
                    assertThat(translations?.start)
                        .isEqualTo((1 - transitionProgress) * maxTranslation)
                    assertThat(translations?.end)
                        .isEqualTo(-(1 - transitionProgress) * maxTranslation)
                assertThat(translations?.start).isEqualTo((1 - transitionProgress) * maxTranslation)
                assertThat(translations?.end).isEqualTo(-(1 - transitionProgress) * maxTranslation)
            }

            unfoldProvider.onTransitionFinishing()
@@ -217,24 +199,20 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
            assertThat(translations?.start).isEqualTo(0f)
            assertThat(translations?.end).isEqualTo(-0f)
        }
        }

    @Test
    fun isContentVisible_whenNotOccluded_visible() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val isContentVisible by collectLastValue(underTest.isContentVisible)

            keyguardOcclusionRepository.setShowWhenLockedActivityInfo(false, null)
            runCurrent()
            assertThat(isContentVisible).isTrue()
        }
        }

    @Test
    fun isContentVisible_whenOccluded_notVisible() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val isContentVisible by collectLastValue(underTest.isContentVisible)

            keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, null)
@@ -245,12 +223,10 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
            runCurrent()
            assertThat(isContentVisible).isFalse()
        }
        }

    @Test
    fun isContentVisible_whenOccluded_notVisible_evenIfShadeShown() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val isContentVisible by collectLastValue(underTest.isContentVisible)

            keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, null)
@@ -264,12 +240,26 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
            runCurrent()
            assertThat(isContentVisible).isFalse()
        }

    @Test
    fun activate_setsDelegate_onKeyguardTransitionAnimationCallbackDelegator() =
        kosmos.runTest {
            runCurrent()
            assertThat(keyguardTransitionAnimationCallbackDelegator.delegate)
                .isSameInstanceAs(fakeKeyguardTransitionAnimationCallback)
        }

    @Test
    fun deactivate_clearsDelegate_onKeyguardTransitionAnimationCallbackDelegator() =
        kosmos.runTest {
            activationJob.cancel()
            runCurrent()
            assertThat(keyguardTransitionAnimationCallbackDelegator.delegate).isNull()
        }

    @Test
    fun isContentVisible_whenOccluded_notVisibleInOccluded_visibleInAod() =
        with(kosmos) {
            testScope.runTest {
        kosmos.runTest {
            val isContentVisible by collectLastValue(underTest.isContentVisible)
            keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, null)
            fakeKeyguardTransitionRepository.transitionTo(
@@ -282,10 +272,7 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa
            runCurrent()
            assertThat(isContentVisible).isFalse()

                fakeKeyguardTransitionRepository.transitionTo(
                    KeyguardState.OCCLUDED,
                    KeyguardState.AOD,
                )
            fakeKeyguardTransitionRepository.transitionTo(KeyguardState.OCCLUDED, KeyguardState.AOD)
            runCurrent()

            sceneInteractor.snapToScene(Scenes.Lockscreen, "")
@@ -293,7 +280,6 @@ class LockscreenContentViewModelTest(flags: FlagsParameterization) : SysuiTestCa

            assertThat(isContentVisible).isTrue()
        }
        }

    private fun prepareConfiguration(): Int {
        val configuration = context.resources.configuration
+6 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.bouncer.dagger

import com.android.systemui.CoreStartable
import com.android.systemui.bouncer.domain.interactor.BouncerMessageAuditLogger
import com.android.systemui.bouncer.log.BouncerLoggerStartable
import dagger.Binds
import dagger.Module
@@ -30,4 +31,9 @@ interface BouncerLoggerModule {
    @IntoMap
    @ClassKey(BouncerLoggerStartable::class)
    fun bindBouncerLoggerStartable(impl: BouncerLoggerStartable): CoreStartable

    @Binds
    @IntoMap
    @ClassKey(BouncerMessageAuditLogger::class)
    fun bind(impl: BouncerMessageAuditLogger): CoreStartable
}
Loading