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

Commit f734bd68 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 14032571 from adf303d7 to 25Q4-release

Change-Id: I9e54848b612068b35bc4f8fcd2af6a408a24b747
parents 5cd5c015 adf303d7
Loading
Loading
Loading
Loading
+17 −28
Original line number Diff line number Diff line
@@ -70,7 +70,12 @@ class MotionValueCollection(
     * [MotionValueCollection] is kept active.
     */
    fun create(spec: () -> MotionSpec, label: String? = null): ManagedMotionValue {
        return ManagedMotionComputation(this, spec, label).also { managedComputations.add(it) }
        return ManagedMotionComputation(this, spec, label).also {
            if (isActive) {
                it.onActivate()
            }
            managedComputations.add(it)
        }
    }

    /**
@@ -96,12 +101,7 @@ class MotionValueCollection(
            var capturedGestureDragOffset = currentGestureDragOffset
            var capturedDirection = currentDirection

            val activeComputations = mutableSetOf<ManagedMotionComputation>()
            managedComputations.forEach {
                it.onActivate()
                activeComputations.add(it)
            }
            activeComputationCount = activeComputations.size
            managedComputations.forEach { it.onActivate() }

            try {
                isAnimating = true
@@ -115,17 +115,6 @@ class MotionValueCollection(
                while (true) {

                    withFrameNanos { frameTimeNanos ->
                        val addedComputations = managedComputations - activeComputations
                        val removedComputations = activeComputations - managedComputations
                        addedComputations.forEach {
                            it.onActivate()
                            activeComputations.add(it)
                        }
                        removedComputations.forEach {
                            it.onDeactivate()
                            activeComputations.remove(it)
                        }
                        activeComputationCount = activeComputations.size
                        frameCount++

                        currentAnimationTimeNanos = frameTimeNanos
@@ -137,7 +126,7 @@ class MotionValueCollection(
                        currentDirection = gestureContext.direction
                        currentGestureDragOffset = gestureContext.dragOffset

                        activeComputations.forEach { it.onFrameStart() }
                        managedComputations.forEach { it.onFrameStart() }
                    }

                    // At this point, the complete frame is done (including layout, drawing and
@@ -152,7 +141,7 @@ class MotionValueCollection(
                    // re-computation if the current state is being read before the next frame).

                    var scheduleNextFrame = false
                    activeComputations.forEach {
                    managedComputations.forEach {
                        if (it.onFrameEnd(isAnimatingUninterrupted)) {
                            scheduleNextFrame = true
                        }
@@ -181,7 +170,9 @@ class MotionValueCollection(
                    }

                    isAnimating = false
                    activeComputations.forEach { it.debugInspector?.isAnimating = false }
                    managedComputations.forEach { it.debugInspector?.isAnimating = false }
                    val activeComputations = managedComputations.toSet()

                    snapshotFlow {
                            val hasComputations =
                                activeComputations.isNotEmpty() || managedComputations.isNotEmpty()
@@ -197,12 +188,11 @@ class MotionValueCollection(
                        }
                        .first { it }
                    isAnimating = true
                    activeComputations.forEach { it.debugInspector?.isAnimating = true }
                    managedComputations.forEach { it.debugInspector?.isAnimating = true }
                }
            } finally {
                isActive = false
                activeComputations.forEach { it.onDeactivate() }
                activeComputationCount = 0
                managedComputations.forEach { it.onDeactivate() }
            }
        }
    }
@@ -241,10 +231,6 @@ class MotionValueCollection(
    var frameCount = 0
        private set

    @VisibleForTesting
    var activeComputationCount = 0
        private set

    @VisibleForTesting
    // Note - this is public so that its accessible by the mechanics:testing library
    val managedMotionValues: Set<ManagedMotionValue>
@@ -252,6 +238,7 @@ class MotionValueCollection(

    internal fun onDispose(toDispose: ManagedMotionComputation) {
        managedComputations.remove(toDispose)
        toDispose.onDeactivate()
    }
}

@@ -399,6 +386,8 @@ internal class ManagedMotionComputation(
        capturedAnimation = currentComputedValues.animation
        capturedSpringState = currentSpringState

        onFrameStart()

        debugInspector?.isAnimating = true
        debugInspector?.isActive = true
    }
+48 −31
Original line number Diff line number Diff line
@@ -69,18 +69,52 @@ class MotionValueCollectionLifecycleTest :
    }

    @Test
    fun keepRunning_activatesExisting() = runTest {
    fun create_withoutKeepRunning_remainsInactive() = runTest {
        val input = mutableFloatStateOf(1f)
        val underTest = MotionValueCollection(input::value, FakeGestureContext)

        rule.setContent {}

        assertThat(underTest.isActive).isFalse()

        val motionValue = underTest.create({ MotionSpec.Identity })
        assertThat(motionValue.output).isNaN()
        val inspector = motionValue.debugInspector()
        assertThat(inspector.isActive).isFalse()
    }

    @Test
    fun create_whileKeepRunning_isActivatedImmediately() = runTest {
        val input = mutableFloatStateOf(1f)
        val underTest = MotionValueCollection(input::value, FakeGestureContext)

        rule.setContent { LaunchedEffect(Unit) { underTest.keepRunning() } }
        rule.awaitIdle()

        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.managedMotionValues.size).isEqualTo(0)

        val motionValue = underTest.create({ MotionSpec.Identity })
        assertThat(motionValue.output).isEqualTo(1f)
        val inspector = motionValue.debugInspector()
        assertThat(inspector.isActive).isTrue()
    }

    @Test
    fun keepRunning_activatesAlreadyCreated() = runTest {
        val input = mutableFloatStateOf(0f)
        val underTest = MotionValueCollection(input::value, FakeGestureContext)

        val inspector = underTest.create({ MotionSpec.Identity }).debugInspector()
        val motionValue = underTest.create({ MotionSpec.Identity })
        val inspector = motionValue.debugInspector()

        assertThat(underTest.frameCount).isEqualTo(0)
        assertThat(underTest.isActive).isFalse()
        assertThat(underTest.isAnimating).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(0)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)
        assertThat(inspector.isActive).isFalse()
        assertThat(inspector.isAnimating).isFalse()
        assertThat(motionValue.output).isNaN()

        rule.setContent { LaunchedEffect(Unit) { underTest.keepRunning() } }

@@ -89,9 +123,10 @@ class MotionValueCollectionLifecycleTest :
        assertThat(underTest.frameCount).isEqualTo(1)
        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.isAnimating).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(1)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)
        assertThat(inspector.isActive).isTrue()
        assertThat(inspector.isAnimating).isFalse()
        assertThat(motionValue.output).isFinite()
    }

    @Test
@@ -109,7 +144,7 @@ class MotionValueCollectionLifecycleTest :
        assertThat(underTest.frameCount).isEqualTo(1)
        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.isAnimating).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(1)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)
        assertThat(inspector.isActive).isTrue()
        assertThat(inspector.isAnimating).isFalse()

@@ -119,7 +154,7 @@ class MotionValueCollectionLifecycleTest :
        assertThat(underTest.frameCount).isEqualTo(2)
        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.isAnimating).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(0)
        assertThat(underTest.managedMotionValues.size).isEqualTo(0)
        assertThat(inspector.isActive).isFalse()
        assertThat(inspector.isAnimating).isFalse()
    }
@@ -138,32 +173,14 @@ class MotionValueCollectionLifecycleTest :

        assertThat(underTest.isActive).isFalse()
        assertThat(inspector.isActive).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(0)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)

        motionValue.dispose()
        rule.awaitIdle()

        assertThat(underTest.isActive).isFalse()
        assertThat(inspector.isActive).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(0)
    }

    @Test
    fun keepRunning_activatesNew() = runTest {
        val input = mutableFloatStateOf(0f)
        val underTest = MotionValueCollection(input::value, FakeGestureContext)

        rule.setContent { LaunchedEffect(Unit) { underTest.keepRunning() } }
        rule.awaitIdle()

        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.activeComputationCount).isEqualTo(0)

        val inspector = underTest.create({ MotionSpec.Identity }).debugInspector()
        rule.awaitIdle()

        assertThat(underTest.activeComputationCount).isEqualTo(1)
        assertThat(inspector.isActive).isTrue()
        assertThat(underTest.managedMotionValues.size).isEqualTo(0)
    }

    @Test
@@ -180,21 +197,21 @@ class MotionValueCollectionLifecycleTest :
        rule.awaitIdle()

        assertThat(underTest.isActive).isTrue()
        assertThat(underTest.activeComputationCount).isEqualTo(2)
        assertThat(underTest.managedMotionValues.size).isEqualTo(2)
        assertThat(inspector1.isActive).isTrue()
        assertThat(inspector2.isActive).isTrue()

        mv1.dispose()
        rule.awaitIdle()

        assertThat(underTest.activeComputationCount).isEqualTo(1)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)
        assertThat(inspector1.isActive).isFalse()
        assertThat(inspector2.isActive).isTrue()

        mv2.dispose()
        rule.awaitIdle()

        assertThat(underTest.activeComputationCount).isEqualTo(0)
        assertThat(underTest.managedMotionValues.size).isEqualTo(0)
        assertThat(inspector1.isActive).isFalse()
        assertThat(inspector2.isActive).isFalse()
    }
@@ -215,14 +232,14 @@ class MotionValueCollectionLifecycleTest :

        assertThat(underTest.isActive).isTrue()
        assertThat(inspector.isActive).isTrue()
        assertThat(underTest.activeComputationCount).isEqualTo(1)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)

        keepRunning.value = false
        rule.awaitIdle()

        assertThat(underTest.isActive).isFalse()
        assertThat(inspector.isActive).isFalse()
        assertThat(underTest.activeComputationCount).isEqualTo(0)
        assertThat(underTest.managedMotionValues.size).isEqualTo(1)
    }

    @Test
+22 −20
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.monet;

import android.annotation.ColorInt;
import android.app.WallpaperColors;
import android.content.theming.ThemeStyle;
import android.graphics.Color;

import com.android.internal.graphics.ColorUtils;
@@ -53,7 +54,7 @@ public class ColorScheme {
    @ColorInt
    private final int mSeed;
    private final boolean mIsDark;
    @Style.Type
    @ThemeStyle.Type
    private final int mStyle;
    private final DynamicScheme mMaterialScheme;
    private final TonalPalette mAccent1;
@@ -65,7 +66,7 @@ public class ColorScheme {
    private final Hct mProposedSeedHct;


    public ColorScheme(@ColorInt int seed, boolean isDark, @Style.Type int style,
    public ColorScheme(@ColorInt int seed, boolean isDark, @ThemeStyle.Type int style,
            double contrastLevel) {

        this.mSeed = seed;
@@ -76,23 +77,23 @@ public class ColorScheme {
        Hct seedHct = Hct.fromInt(
                seed == Color.TRANSPARENT
                        ? GOOGLE_BLUE
                        : (style != Style.CONTENT
                        : (style != ThemeStyle.CONTENT
                                && mProposedSeedHct.getChroma() < 5
                                ? GOOGLE_BLUE
                                : seed));

        mMaterialScheme = switch (style) {
            case Style.SPRITZ -> new SchemeNeutral(seedHct, isDark, contrastLevel);
            case Style.TONAL_SPOT -> new SchemeTonalSpot(seedHct, isDark, contrastLevel);
            case Style.VIBRANT -> new SchemeVibrant(seedHct, isDark, contrastLevel);
            case Style.EXPRESSIVE -> new SchemeExpressive(seedHct, isDark, contrastLevel);
            case Style.RAINBOW -> new SchemeRainbow(seedHct, isDark, contrastLevel);
            case Style.FRUIT_SALAD -> new SchemeFruitSalad(seedHct, isDark, contrastLevel);
            case Style.CONTENT -> new SchemeContent(seedHct, isDark, contrastLevel);
            case Style.MONOCHROMATIC -> new SchemeMonochrome(seedHct, isDark, contrastLevel);
            case ThemeStyle.SPRITZ -> new SchemeNeutral(seedHct, isDark, contrastLevel);
            case ThemeStyle.TONAL_SPOT -> new SchemeTonalSpot(seedHct, isDark, contrastLevel);
            case ThemeStyle.VIBRANT -> new SchemeVibrant(seedHct, isDark, contrastLevel);
            case ThemeStyle.EXPRESSIVE -> new SchemeExpressive(seedHct, isDark, contrastLevel);
            case ThemeStyle.RAINBOW -> new SchemeRainbow(seedHct, isDark, contrastLevel);
            case ThemeStyle.FRUIT_SALAD -> new SchemeFruitSalad(seedHct, isDark, contrastLevel);
            case ThemeStyle.CONTENT -> new SchemeContent(seedHct, isDark, contrastLevel);
            case ThemeStyle.MONOCHROMATIC -> new SchemeMonochrome(seedHct, isDark, contrastLevel);
            // SystemUI Schemes
            case Style.CLOCK -> new SchemeClock(seedHct, isDark, contrastLevel);
            case Style.CLOCK_VIBRANT -> new SchemeClockVibrant(seedHct, isDark, contrastLevel);
            case ThemeStyle.CLOCK -> new SchemeClock(seedHct, isDark, contrastLevel);
            case ThemeStyle.CLOCK_VIBRANT -> new SchemeClockVibrant(seedHct, isDark, contrastLevel);
            default -> throw new IllegalArgumentException("Unknown style: " + style);
        };

@@ -105,19 +106,20 @@ public class ColorScheme {
    }

    public ColorScheme(@ColorInt int seed, boolean darkTheme) {
        this(seed, darkTheme, Style.TONAL_SPOT);
        this(seed, darkTheme, ThemeStyle.TONAL_SPOT);
    }

    public ColorScheme(@ColorInt int seed, boolean darkTheme, @Style.Type int style) {
    public ColorScheme(@ColorInt int seed, boolean darkTheme, @ThemeStyle.Type int style) {
        this(seed, darkTheme, style, 0.0);
    }

    public ColorScheme(WallpaperColors wallpaperColors, boolean darkTheme, @Style.Type int style) {
        this(getSeedColor(wallpaperColors, style != Style.CONTENT), darkTheme, style);
    public ColorScheme(WallpaperColors wallpaperColors, boolean darkTheme,
            @ThemeStyle.Type int style) {
        this(getSeedColor(wallpaperColors, style != ThemeStyle.CONTENT), darkTheme, style);
    }

    public ColorScheme(WallpaperColors wallpaperColors, boolean darkTheme) {
        this(wallpaperColors, darkTheme, Style.TONAL_SPOT);
        this(wallpaperColors, darkTheme, ThemeStyle.TONAL_SPOT);
    }

    public int getBackgroundColor() {
@@ -140,7 +142,7 @@ public class ColorScheme {
        return mSeed;
    }

    @Style.Type
    @ThemeStyle.Type
    public int getStyle() {
        return mStyle;
    }
+0 −183
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.monet;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * A class defining the different styles available for theming.
 * This class replaces the previous enum implementation for improved performance and compatibility.
 */
public final class Style {

    private Style() {
    }

    /**
     * @hide
     */
    @IntDef({
            SPRITZ,
            TONAL_SPOT,
            VIBRANT,
            EXPRESSIVE,
            RAINBOW,
            FRUIT_SALAD,
            CONTENT,
            MONOCHROMATIC,
            CLOCK,
            CLOCK_VIBRANT
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface Type {
    }

    /**
     * Represents the SPRITZ style.
     */
    public static final int SPRITZ = 0;
    /**
     * Represents the TONAL_SPOT style.
     */
    public static final int TONAL_SPOT = 1;
    /**
     * Represents the VIBRANT style.
     */
    public static final int VIBRANT = 2;
    /**
     * Represents the EXPRESSIVE style.
     */
    public static final int EXPRESSIVE = 3;
    /**
     * Represents the RAINBOW style.
     */
    public static final int RAINBOW = 4;
    /**
     * Represents the FRUIT_SALAD style.
     */
    public static final int FRUIT_SALAD = 5;
    /**
     * Represents the CONTENT style.
     */
    public static final int CONTENT = 6;
    /**
     * Represents the MONOCHROMATIC style.
     */
    public static final int MONOCHROMATIC = 7;
    /**
     * Represents the CLOCK style.
     */
    public static final int CLOCK = 8;
    /**
     * Represents the CLOCK_VIBRANT style.
     */
    public static final int CLOCK_VIBRANT = 9;


    /**
     * Returns the string representation of the given style.
     *
     * @param style The style value.
     * @return The string representation of the style.
     * @throws IllegalArgumentException if the style value is invalid.
     */
    @NonNull
    public static String toString(@Nullable @Type Integer style) {
        // Throw an exception if style is null
        if (style == null) {
            throw new IllegalArgumentException("Invalid style value: null");
        }

        return switch (style) {
            case SPRITZ -> "SPRITZ";
            case TONAL_SPOT -> "TONAL_SPOT";
            case VIBRANT -> "VIBRANT";
            case EXPRESSIVE -> "EXPRESSIVE";
            case RAINBOW -> "RAINBOW";
            case FRUIT_SALAD -> "FRUIT_SALAD";
            case CONTENT -> "CONTENT";
            case MONOCHROMATIC -> "MONOCHROMATIC";
            case CLOCK -> "CLOCK";
            case CLOCK_VIBRANT -> "CLOCK_VIBRANT";
            default -> throw new IllegalArgumentException("Invalid style value: " + style);
        };
    }

    /**
     * Returns the style value corresponding to the given style name.
     *
     * @param styleName The name of the style.
     * @return The style value.
     * @throws IllegalArgumentException if the style name is invalid.
     */
    public static @Type int valueOf(@Nullable @NonNull String styleName) {
        if (styleName == null) {
            throw new IllegalArgumentException("Invalid style value: null");
        }

        return switch (styleName) {
            case "SPRITZ" -> SPRITZ;
            case "TONAL_SPOT" -> TONAL_SPOT;
            case "VIBRANT" -> VIBRANT;
            case "EXPRESSIVE" -> EXPRESSIVE;
            case "RAINBOW" -> RAINBOW;
            case "FRUIT_SALAD" -> FRUIT_SALAD;
            case "CONTENT" -> CONTENT;
            case "MONOCHROMATIC" -> MONOCHROMATIC;
            case "CLOCK" -> CLOCK;
            case "CLOCK_VIBRANT" -> CLOCK_VIBRANT;
            default -> throw new IllegalArgumentException("Invalid style name: " + styleName);
        };
    }

    /**
     * Returns the name of the given style. This method is equivalent to {@link #toString(int)}.
     *
     * @param style The style value.
     * @return The name of the style.
     */
    @NonNull
    public static String name(@Type int style) {
        return toString(style);
    }

    /**
     * Returns an array containing all the style values.
     *
     * @return An array of all style values.
     */
    public static int[] values() {
        return new int[]{
                SPRITZ,
                TONAL_SPOT,
                VIBRANT,
                EXPRESSIVE,
                RAINBOW,
                FRUIT_SALAD,
                CONTENT,
                MONOCHROMATIC,
                CLOCK,
                CLOCK_VIBRANT
        };
    }

}
 No newline at end of file
+6 −5
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.systemui.monet

import android.app.WallpaperColors
import android.content.theming.ThemeStyle
import android.graphics.Color
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -113,16 +114,16 @@ class ColorSchemeTest {
                theme.setAttribute("color", sourceColorHex)
                mode.appendChild(theme)

                for (styleValue in Style.values()) {
                for (styleValue in ThemeStyle.values()) {
                    if (
                        styleValue == Style.CLOCK ||
                            styleValue == Style.CLOCK_VIBRANT ||
                            styleValue == Style.CONTENT
                        styleValue == ThemeStyle.CLOCK ||
                            styleValue == ThemeStyle.CLOCK_VIBRANT ||
                            styleValue == ThemeStyle.CONTENT
                    ) {
                        continue
                    }

                    val style = document.createElement(Style.name(styleValue).lowercase())
                    val style = document.createElement(ThemeStyle.name(styleValue).lowercase())
                    val colorScheme =
                        ColorScheme(
                            WallpaperColors(sourceColor, sourceColor, sourceColor),