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

Commit 50ba323d authored by Andreas Miko's avatar Andreas Miko
Browse files

Set traceName automatically for Hydrator

The traceName will automatically be passed as the property name when by
is used. Old `hydratedStateOf` methods are kept to support non-by usage
and explicit traceName.

Usage: `val myState by hydratedStateOf()``

Bug: b/420591935
Test: Refactor only
Flag: com.android.systemui.scene_container
Change-Id: Ibea95a6d37a29c2cd32600d8d87eade105d8b6e9
parent 926b83c0
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -108,4 +108,25 @@ abstract class HydratedActivatable(
    /** @see [Hydrator.hydratedStateOf] */
    protected fun <T> Flow<T>.hydratedStateOf(traceName: String, initialValue: T): State<T> =
        hydrator.hydratedStateOf(traceName, initialValue, this)

    /**
     * Returns a [Hydrator.StateDelegateProvider] which will automatically set the [traceName]. Use
     * with the `by` keyword.
     *
     * Usage: `val myState by hydratedStateOf()`
     *
     * @see [Hydrator.hydratedStateOf]
     */
    protected fun <T> StateFlow<T>.hydratedStateOf() = hydrator.hydratedStateOf(this)

    /**
     * Returns a [Hydrator.StateDelegateProvider] which will automatically set the [traceName]. Use
     * with the `by` keyword.
     *
     * Usage: `val myState by hydratedStateOf(initialValue)`
     *
     * @see [Hydrator.hydratedStateOf]
     */
    protected fun <T> Flow<T>.hydratedStateOf(initialValue: T) =
        hydrator.hydratedStateOf(initialValue, this)
}
+59 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import androidx.compose.runtime.snapshots.StateFactoryMarker
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.app.tracing.coroutines.traceCoroutine
import com.android.systemui.log.table.TableLogBuffer
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
@@ -140,4 +142,61 @@ class Hydrator(
    }

    private data class NamedActivatable(val traceName: String?, val activatable: Activatable)

    /**
     * Returns a snapshot [State] that's kept up-to-date as long as its owner is active. Returns
     * [StateDelegateProvider] which is used by the `by` keyword. It will automatically set the
     * traceName to be the property name.
     *
     * Usage: `val myState by hydrator.hydratedStateOf(initialValue, source)`
     *
     * @param initialValue The first value to place on the [State]
     * @param source The upstream [Flow] to collect from; values emitted to it will be automatically
     *   set on the returned [State].
     */
    fun <T> hydratedStateOf(initialValue: T, source: Flow<T>): StateDelegateProvider<T> {
        return StateDelegateProvider(initialValue, source)
    }

    /**
     * Returns a snapshot [State] that's kept up-to-date as long as its owner is active. Returns
     * [StateDelegateProvider] which is used by the `by` keyword. It will automatically set the
     * traceName to be the property name.
     *
     * Usage: `val myState by hydrator.hydratedStateOf(source)`
     *
     * @param initialValue The first value to place on the [State]
     * @param source The upstream [Flow] to collect from; values emitted to it will be automatically
     *   set on the returned [State].
     */
    fun <T> hydratedStateOf(source: StateFlow<T>): StateDelegateProvider<T> {
        return StateDelegateProvider(source.value, source)
    }

    inner class StateDelegateProvider<T>
    internal constructor(
        private val initialValue: T,
        private val sourceFlow: Flow<T>,
        private val explicitTraceName: String? = null,
    ) {
        operator fun provideDelegate(
            thisRef: Any?,
            property: KProperty<*>,
        ): ReadOnlyProperty<Any?, T> {
            val finalTraceName = explicitTraceName ?: property.name

            val internalState: State<T> =
                hydratedStateOf(
                    traceName = finalTraceName,
                    initialValue = initialValue,
                    source = sourceFlow,
                )

            return object : ReadOnlyProperty<Any?, T> {
                override fun getValue(thisRef: Any?, property: KProperty<*>): T {
                    return internalState.value
                }
            }
        }
    }
}
+2 −4
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.ui.viewmodel

import androidx.compose.runtime.getValue
import com.android.systemui.lifecycle.HydratedActivatable
import kotlinx.coroutines.awaitCancellation
import kotlinx.coroutines.flow.Flow
@@ -34,10 +33,9 @@ class FakeHydratedViewModel(
    var activationCount = 0
    var cancellationCount = 0

    val stateBackedByFlow: Boolean by
        upstreamFlow.hydratedStateOf(traceName = "test", initialValue = true)
    val stateBackedByFlow by upstreamFlow.hydratedStateOf(initialValue = true)

    val stateBackedByStateFlow: Boolean by upstreamStateFlow.hydratedStateOf(traceName = "test")
    val stateBackedByStateFlow by upstreamStateFlow.hydratedStateOf()

    fun publicEnqueueOnActivatedScope(runnable: suspend () -> Unit) =
        enqueueOnActivatedScope(runnable)