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

Commit cba28b4a authored by Bharat Singh's avatar Bharat Singh Committed by Android (Google) Code Review
Browse files

Merge "[SysUI][Floaty] Increase initial delay of invocation effect based on...

Merge "[SysUI][Floaty] Increase initial delay of invocation effect based on LPP duration in Settings" into main
parents c667ea50 fdb28e95
Loading
Loading
Loading
Loading
+61 −7
Original line number Diff line number Diff line
@@ -30,14 +30,14 @@ import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.testScope
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
import com.android.systemui.topwindoweffects.data.repository.DEFAULT_INITIAL_DELAY_MILLIS
import com.android.systemui.topwindoweffects.data.repository.DEFAULT_LONG_PRESS_POWER_DURATION_MILLIS
import com.android.systemui.topwindoweffects.data.repository.fakeSqueezeEffectRepository
import com.android.systemui.topwindoweffects.domain.interactor.SqueezeEffectInteractor
import com.android.systemui.topwindoweffects.ui.compose.EffectsWindowRoot
import com.android.systemui.topwindoweffects.ui.viewmodel.SqueezeEffectViewModel
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.runCurrent
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -74,7 +74,7 @@ class TopLevelWindowEffectsTest : SysuiTestCase() {
            )
        }

    private fun Kosmos.waitFor(duration: Duration) {
    private fun Kosmos.advanceTime(duration: Duration) {
        advanceTimeBy(duration)
        runCurrent()
    }
@@ -101,12 +101,15 @@ class TopLevelWindowEffectsTest : SysuiTestCase() {
    @Test
    fun addViewToWindowWhenSqueezeEffectEnabled_withDelayMoreThan100Millis() =
        kosmos.runTest {
            val expectedDelay = 100L
            fakeSqueezeEffectRepository.isSqueezeEffectEnabled.value = true
            fakeSqueezeEffectRepository.invocationEffectInitialDelayMs = expectedDelay
            fakeKeyEventRepository.setPowerButtonDown(true)

            underTest.start()

            waitFor(101.milliseconds)
            // add additional 1ms time to simulate initial delay duration has passed
            advanceTime((expectedDelay + 1).milliseconds)

            verify(windowManager, times(1)).addView(any<View>(), any<WindowManager.LayoutParams>())
        }
@@ -114,12 +117,15 @@ class TopLevelWindowEffectsTest : SysuiTestCase() {
    @Test
    fun addViewToWindowWhenSqueezeEffectEnabled_withDelayLessThan100Millis() =
        kosmos.runTest {
            val expectedDelay = 100L
            fakeSqueezeEffectRepository.isSqueezeEffectEnabled.value = true
            fakeSqueezeEffectRepository.invocationEffectInitialDelayMs = expectedDelay
            fakeKeyEventRepository.setPowerButtonDown(true)

            underTest.start()

            waitFor(99.milliseconds)
            // subtract 1ms time to simulate initial delay duration is yet not finished
            advanceTime((expectedDelay - 1).milliseconds)

            verify(windowManager, never()).addView(any<View>(), any<WindowManager.LayoutParams>())
        }
@@ -127,12 +133,15 @@ class TopLevelWindowEffectsTest : SysuiTestCase() {
    @Test
    fun addViewToWindowWhenSqueezeEffectEnabled_upEventReceivedBefore100Millis() =
        kosmos.runTest {
            val expectedDelay = 100L
            fakeSqueezeEffectRepository.isSqueezeEffectEnabled.value = true
            fakeSqueezeEffectRepository.invocationEffectInitialDelayMs = expectedDelay
            fakeKeyEventRepository.setPowerButtonDown(true)

            underTest.start()

            waitFor(99.milliseconds)
            // subtract 1ms time to simulate initial delay duration is yet not finished
            advanceTime((expectedDelay - 1).milliseconds)

            fakeKeyEventRepository.setPowerButtonDown(false)

@@ -144,12 +153,15 @@ class TopLevelWindowEffectsTest : SysuiTestCase() {
    @Test
    fun addViewToWindowWhenSqueezeEffectEnabled_upEventReceivedAfter100Millis() =
        kosmos.runTest {
            val expectedDelay = 100L
            fakeSqueezeEffectRepository.isSqueezeEffectEnabled.value = true
            fakeSqueezeEffectRepository.invocationEffectInitialDelayMs = expectedDelay
            fakeKeyEventRepository.setPowerButtonDown(true)

            underTest.start()

            waitFor(101.milliseconds)
            // add additional 1ms time to simulate initial delay duration has passed
            advanceTime((expectedDelay + 1).milliseconds)

            fakeKeyEventRepository.setPowerButtonDown(false)

@@ -157,4 +169,46 @@ class TopLevelWindowEffectsTest : SysuiTestCase() {

            verify(windowManager, times(1)).addView(any<View>(), any<WindowManager.LayoutParams>())
        }

    @Test
    fun addViewToWindowWhenSqueezeEffectEnabled_upEventReceivedAfterLpp_withIncreasedLppDuration_afterInitialDelay() =
        kosmos.runTest {
            val expectedDelay =
                DEFAULT_INITIAL_DELAY_MILLIS + 750 - DEFAULT_LONG_PRESS_POWER_DURATION_MILLIS
            fakeSqueezeEffectRepository.isSqueezeEffectEnabled.value = true
            fakeSqueezeEffectRepository.invocationEffectInitialDelayMs = expectedDelay
            fakeKeyEventRepository.setPowerButtonDown(true)

            underTest.start()

            // add additional 1ms time to simulate initial delay duration has passed
            advanceTime((expectedDelay + 1).milliseconds)

            fakeKeyEventRepository.setPowerButtonDown(false)

            runCurrent()

            verify(windowManager, times(1)).addView(any<View>(), any<WindowManager.LayoutParams>())
        }

    @Test
    fun addViewToWindowWhenSqueezeEffectEnabled_upEventReceivedAfterLpp_withIncreasedLppDuration_beforeInitialDelay() =
        kosmos.runTest {
            val expectedDelay =
                DEFAULT_INITIAL_DELAY_MILLIS + 750 - DEFAULT_LONG_PRESS_POWER_DURATION_MILLIS
            fakeSqueezeEffectRepository.isSqueezeEffectEnabled.value = true
            fakeSqueezeEffectRepository.invocationEffectInitialDelayMs = expectedDelay
            fakeKeyEventRepository.setPowerButtonDown(true)

            underTest.start()

            // subtract 1ms time to simulate initial delay duration is yet not finished
            advanceTime((expectedDelay - 1).milliseconds)

            fakeKeyEventRepository.setPowerButtonDown(false)

            runCurrent()

            verify(windowManager, never()).addView(any<View>(), any<WindowManager.LayoutParams>())
        }
}
+37 −23
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.graphics.PixelFormat
import android.view.Gravity
import android.view.WindowInsets
import android.view.WindowManager
import androidx.annotation.DrawableRes
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -51,32 +52,53 @@ constructor(
    private val viewModelFactory: SqueezeEffectViewModel.Factory,
) : CoreStartable {

    private var root: EffectsWindowRoot? = null

    override fun start() {
        applicationScope.launch {
            var root: EffectsWindowRoot? = null
            var launchWindowEffect: Job? = null
            squeezeEffectInteractor.isSqueezeEffectEnabled.collectLatest { enabled ->
                if (enabled) {
                    keyEventInteractor.isPowerButtonDown.collectLatest { down ->
                        // cancel creating effects window if UP event is received within timeout
                        // threshold of 100 milliseconds
                        // threshold of initial delay
                        launchWindowEffect?.cancel()
                        if (down) {
                            val roundedCornerId =
                                async(context = bgContext) {
                                    squeezeEffectInteractor.getRoundedCornersResourceId()
                                }
                            val initialDelay =
                                async(context = bgContext) {
                                    squeezeEffectInteractor.getInvocationEffectInitialDelayMs()
                                }
                            launchWindowEffect = launch {
                                delay(100) // delay to invoke the squeeze effect
                                delay(initialDelay.await())
                                addWindow(
                                    roundedCornerId.await().top,
                                    roundedCornerId.await().bottom,
                                )
                            }
                        } else {
                            launchWindowEffect = null
                        }
                    }
                }
            }
        }
    }

    private fun addWindow(
        @DrawableRes topRoundedCornerId: Int,
        @DrawableRes bottomRoundedCornerId: Int,
    ) {
        if (root == null) {
            root =
                EffectsWindowRoot(
                    context = context,
                    viewModelFactory = viewModelFactory,
                                            topRoundedCornerResourceId =
                                                roundedCornerId.await().top,
                                            bottomRoundedCornerResourceId =
                                                roundedCornerId.await().bottom,
                    topRoundedCornerResourceId = topRoundedCornerId,
                    bottomRoundedCornerResourceId = bottomRoundedCornerId,
                    onEffectFinished = {
                        if (root?.isAttachedToWindow == true) {
                            windowManager.removeView(root)
@@ -84,16 +106,8 @@ constructor(
                        }
                    },
                )
                                    root?.let {
                                        windowManager.addView(it, getWindowManagerLayoutParams())
                                    }
                                }
                            }
                        } else {
                            launchWindowEffect = null
                        }
                    }
                }
            root?.let { rootView ->
                windowManager.addView(rootView, getWindowManagerLayoutParams())
            }
        }
    }
+2 −0
Original line number Diff line number Diff line
@@ -22,5 +22,7 @@ import kotlinx.coroutines.flow.Flow
interface SqueezeEffectRepository {
    val isSqueezeEffectEnabled: Flow<Boolean>

    suspend fun getInvocationEffectInitialDelayMs(): Long

    suspend fun getRoundedCornersResourceId(): SqueezeEffectCornerResourceId
}
+23 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.database.ContentObserver
import android.os.Bundle
import android.os.Handler
import android.provider.Settings.Global.POWER_BUTTON_LONG_PRESS
import android.provider.Settings.Global.POWER_BUTTON_LONG_PRESS_DURATION_MS
import android.util.DisplayUtils
import android.view.DisplayInfo
import androidx.annotation.ArrayRes
@@ -47,6 +48,8 @@ import kotlinx.coroutines.flow.flowOn
@VisibleForTesting
const val SET_INVOCATION_EFFECT_PARAMETERS_ACTION = "set_invocation_effect_parameters"
@VisibleForTesting const val IS_INVOCATION_EFFECT_ENABLED_KEY = "is_invocation_effect_enabled"
@VisibleForTesting const val DEFAULT_INITIAL_DELAY_MILLIS = 100L
@VisibleForTesting const val DEFAULT_LONG_PRESS_POWER_DURATION_MILLIS = 500L

@SysUISingleton
class SqueezeEffectRepositoryImpl
@@ -80,6 +83,16 @@ constructor(
            }
            .flowOn(bgCoroutineContext)

    override suspend fun getInvocationEffectInitialDelayMs(): Long {
        val duration = getLongPressPowerDurationFromSettings()
        // TODO(b/408363187): adjust this difference for values lower than 500ms
        return if (duration > DEFAULT_LONG_PRESS_POWER_DURATION_MILLIS) {
            DEFAULT_INITIAL_DELAY_MILLIS + (duration - DEFAULT_LONG_PRESS_POWER_DURATION_MILLIS)
        } else {
            DEFAULT_INITIAL_DELAY_MILLIS
        }
    }

    override suspend fun getRoundedCornersResourceId(): SqueezeEffectCornerResourceId {
        val displayInfo = DisplayInfo()
        context.display.getDisplayInfo(displayInfo)
@@ -138,6 +151,16 @@ constructor(
            ),
        ) == 5 // 5 corresponds to launch assistant in PhoneWindowManager.java

    private fun getLongPressPowerDurationFromSettings() =
        globalSettings
            .getInt(
                POWER_BUTTON_LONG_PRESS_DURATION_MS,
                context.resources.getInteger(
                    com.android.internal.R.integer.config_longPressOnPowerDurationMs
                ),
            )
            .toLong()

    override fun tryHandleSetUiHints(hints: Bundle): Boolean {
        return when (hints.getString(AssistManager.ACTION_KEY)) {
            SET_INVOCATION_EFFECT_PARAMETERS_ACTION -> {
+3 −0
Original line number Diff line number Diff line
@@ -26,6 +26,9 @@ class SqueezeEffectInteractor
constructor(private val squeezeEffectRepository: SqueezeEffectRepository) {
    val isSqueezeEffectEnabled = squeezeEffectRepository.isSqueezeEffectEnabled

    suspend fun getInvocationEffectInitialDelayMs() =
        squeezeEffectRepository.getInvocationEffectInitialDelayMs()

    suspend fun getRoundedCornersResourceId() =
        squeezeEffectRepository.getRoundedCornersResourceId()
}
Loading