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

Commit b3ab539b authored by Lucas Silva's avatar Lucas Silva
Browse files

Fix live timers flickering when pausing

This change adds a flag which uses a stable id as the key for timers,
instead of using the smartspace target id. The stable id stays the same
when pausing/playing timers, which allows us to re-use the existing
AndroidView of the timer instead of creating a new one.

Bug: 353801573
Test: atest SystemUiRoboTests
Flag: com.android.systemui.communal_timer_flicker_fix
Change-Id: I1124a9148ddd635899eb5d9f6780cd49add9f232
parent 31a1125d
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1004,6 +1004,16 @@ flag {
  }
}

flag {
  name: "communal_timer_flicker_fix"
  namespace: "systemui"
  description: "fixes timers on the hub flickering when pausing"
  bug: "353801573"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
  name: "app_clips_backlinks"
  namespace: "systemui"
+9 −1
Original line number Diff line number Diff line
@@ -152,6 +152,7 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.unit.times
import androidx.compose.ui.util.fastAll
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.viewinterop.NoOpUpdate
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.window.layout.WindowMetricsCalculator
import com.android.compose.animation.Easings.Emphasized
@@ -159,6 +160,7 @@ import com.android.compose.modifiers.thenIf
import com.android.compose.theme.LocalAndroidColorScheme
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
import com.android.internal.R.dimen.system_app_widget_background_radius
import com.android.systemui.Flags.communalTimerFlickerFix
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalContentSize
import com.android.systemui.communal.shared.model.CommunalScenes
@@ -1336,9 +1338,15 @@ private fun SmartspaceContent(
        factory = { context ->
            SmartspaceAppWidgetHostView(context).apply {
                interactionHandler?.let { setInteractionHandler(it) }
                if (!communalTimerFlickerFix()) {
                    updateAppWidget(model.remoteViews)
                }
            }
        },
        update =
            if (communalTimerFlickerFix()) {
                { view: SmartspaceAppWidgetHostView -> view.updateAppWidget(model.remoteViews) }
            } else NoOpUpdate,
        // For reusing composition in lazy lists.
        onReset = {},
    )
+44 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_COMMUNAL_TIMER_FLICKER_FIX
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.smartspace.CommunalSmartspaceController
import com.android.systemui.concurrency.fakeExecutor
@@ -97,6 +98,7 @@ class CommunalSmartspaceRepositoryImplTest : SysuiTestCase() {
        }

    @EnableFlags(FLAG_REMOTE_VIEWS)
    @DisableFlags(FLAG_COMMUNAL_TIMER_FLICKER_FIX)
    @Test
    fun communalTimers_onlyShowTimersWithRemoteViews() =
        testScope.runTest {
@@ -138,6 +140,48 @@ class CommunalSmartspaceRepositoryImplTest : SysuiTestCase() {
            assertThat(communalTimers?.first()?.smartspaceTargetId).isEqualTo("timer-1-started")
        }

    @EnableFlags(FLAG_REMOTE_VIEWS, FLAG_COMMUNAL_TIMER_FLICKER_FIX)
    @Test
    fun communalTimers_onlyShowTimersWithRemoteViews_timerFlickerFix() =
        testScope.runTest {
            underTest.startListening()

            val communalTimers by collectLastValue(underTest.timers)
            runCurrent()
            fakeExecutor.runAllReady()

            with(captureSmartspaceTargetListener()) {
                onSmartspaceTargetsUpdated(
                    listOf(
                        // Invalid. Not a timer
                        mock<SmartspaceTarget> {
                            on { smartspaceTargetId }.doReturn("weather")
                            on { featureType }.doReturn(SmartspaceTarget.FEATURE_WEATHER)
                        },
                        // Invalid. RemoteViews absent
                        mock<SmartspaceTarget> {
                            on { smartspaceTargetId }.doReturn("timer-0-started")
                            on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
                            on { remoteViews }.doReturn(null)
                            on { creationTimeMillis }.doReturn(1000)
                        },
                        // Valid
                        mock<SmartspaceTarget> {
                            on { smartspaceTargetId }.doReturn("timer-1-started")
                            on { featureType }.doReturn(SmartspaceTarget.FEATURE_TIMER)
                            on { remoteViews }.doReturn(mock())
                            on { creationTimeMillis }.doReturn(2000)
                        },
                    )
                )
            }
            runCurrent()

            // Verify that only the valid target is listed
            assertThat(communalTimers).hasSize(1)
            assertThat(communalTimers?.first()?.smartspaceTargetId).isEqualTo("timer-1")
        }

    @EnableFlags(FLAG_REMOTE_VIEWS)
    @Test
    fun communalTimers_cacheCreationTime() =
+3 −1
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.communal.data.repository
import android.app.smartspace.SmartspaceTarget
import android.os.Parcelable
import androidx.annotation.VisibleForTesting
import com.android.systemui.Flags.communalTimerFlickerFix
import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
import com.android.systemui.communal.smartspace.CommunalSmartspaceController
import com.android.systemui.dagger.SysUISingleton
@@ -80,7 +81,8 @@ constructor(
                    // The view layer should have the instance based smartspaceTargetId instead of
                    // stable id, so that when a new instance of the timer is created, for example,
                    // when it is paused, the view should re-render its remote views.
                    smartspaceTargetId = target.smartspaceTargetId,
                    smartspaceTargetId =
                        if (communalTimerFlickerFix()) stableId else target.smartspaceTargetId,
                    createdTimestampMillis = targetCreationTimes[stableId]!!,
                    remoteViews = target.remoteViews!!,
                )