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

Commit 58d7a15c authored by Ale Nijamkin's avatar Ale Nijamkin Committed by Automerger Merge Worker
Browse files

Merge "Support animatable icons to quick affordances." into tm-qpr-dev am:...

Merge "Support animatable icons to quick affordances." into tm-qpr-dev am: e155f5c7 am: d3613e2a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/20592357



Change-Id: Id4c71610fde915e1c529dd149063f10f25dd1fc1
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 265ee855 d3613e2a
Loading
Loading
Loading
Loading
+61 −59
Original line number Diff line number Diff line
@@ -21,19 +21,21 @@ import android.content.Context
import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.common.shared.model.ContentDescription
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.statusbar.policy.FlashlightController
import javax.inject.Inject
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject

@SysUISingleton
class FlashlightQuickAffordanceConfig @Inject constructor(
class FlashlightQuickAffordanceConfig
@Inject
constructor(
    @Application private val context: Context,
    private val flashlightController: FlashlightController,
) : KeyguardQuickAffordanceConfig {
@@ -46,7 +48,7 @@ class FlashlightQuickAffordanceConfig @Inject constructor(
            override fun toLockScreenState(): KeyguardQuickAffordanceConfig.LockScreenState =
                KeyguardQuickAffordanceConfig.LockScreenState.Visible(
                    Icon.Resource(
                        R.drawable.ic_flashlight_on,
                        R.drawable.qs_flashlight_icon_on,
                        ContentDescription.Resource(R.string.quick_settings_flashlight_label)
                    ),
                    ActivationState.Active
@@ -57,7 +59,7 @@ class FlashlightQuickAffordanceConfig @Inject constructor(
            override fun toLockScreenState(): KeyguardQuickAffordanceConfig.LockScreenState =
                KeyguardQuickAffordanceConfig.LockScreenState.Visible(
                    Icon.Resource(
                        R.drawable.ic_flashlight_off,
                        R.drawable.qs_flashlight_icon_off,
                        ContentDescription.Resource(R.string.quick_settings_flashlight_label)
                    ),
                    ActivationState.Inactive
@@ -77,15 +79,12 @@ class FlashlightQuickAffordanceConfig @Inject constructor(
        get() = context.getString(R.string.quick_settings_flashlight_label)

    override val pickerIconResourceId: Int
        get() = if (flashlightController.isEnabled) {
            R.drawable.ic_flashlight_on
        } else {
            R.drawable.ic_flashlight_off
        }
        get() = R.drawable.ic_flashlight_off

    override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
        conflatedCallbackFlow {
        val flashlightCallback = object : FlashlightController.FlashlightListener {
            val flashlightCallback =
                object : FlashlightController.FlashlightListener {
                    override fun onFlashlightChanged(enabled: Boolean) {
                        trySendWithFailureLogging(
                            if (enabled) {
@@ -98,7 +97,10 @@ class FlashlightQuickAffordanceConfig @Inject constructor(
                    }

                    override fun onFlashlightError() {
                trySendWithFailureLogging(FlashlightState.OffAvailable.toLockScreenState(), TAG)
                        trySendWithFailureLogging(
                            FlashlightState.OffAvailable.toLockScreenState(),
                            TAG
                        )
                    }

                    override fun onFlashlightAvailabilityChanged(available: Boolean) {
@@ -119,15 +121,15 @@ class FlashlightQuickAffordanceConfig @Inject constructor(

            flashlightController.addCallback(flashlightCallback)

        awaitClose {
            flashlightController.removeCallback(flashlightCallback)
        }
            awaitClose { flashlightController.removeCallback(flashlightCallback) }
        }

    override fun onTriggered(expandable: Expandable?):
            KeyguardQuickAffordanceConfig.OnTriggeredResult {
        flashlightController
                .setFlashlight(flashlightController.isAvailable && !flashlightController.isEnabled)
    override fun onTriggered(
        expandable: Expandable?
    ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
        flashlightController.setFlashlight(
            flashlightController.isAvailable && !flashlightController.isEnabled
        )
        return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
    }

+26 −4
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.keyguard.ui.binder

import android.graphics.drawable.Animatable2
import android.util.Size
import android.util.TypedValue
import android.view.View
@@ -27,12 +28,11 @@ import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.LockIconViewController
import com.android.settingslib.Utils
import com.android.systemui.R
import com.android.systemui.animation.Expandable
import com.android.systemui.animation.Interpolators
import com.android.systemui.common.shared.model.Icon
import com.android.systemui.common.ui.binder.IconViewBinder
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewModel
@@ -73,7 +73,8 @@ object KeyguardBottomAreaViewBinder {
        fun onConfigurationChanged()

        /**
         * Returns whether the keyguard bottom area should be constrained to the top of the lock icon
         * Returns whether the keyguard bottom area should be constrained to the top of the lock
         * icon
         */
        fun shouldConstrainToTopOfLockIcon(): Boolean
    }
@@ -248,6 +249,27 @@ object KeyguardBottomAreaViewBinder {

        IconViewBinder.bind(viewModel.icon, view)

        (view.drawable as? Animatable2)?.let { animatable ->
            (viewModel.icon as? Icon.Resource)?.res?.let { iconResourceId ->
                // Always start the animation (we do call stop() below, if we need to skip it).
                animatable.start()

                if (view.tag != iconResourceId) {
                    // Here when we haven't run the animation on a previous update.
                    //
                    // Save the resource ID for next time, so we know not to re-animate the same
                    // animation again.
                    view.tag = iconResourceId
                } else {
                    // Here when we've already done this animation on a previous update and want to
                    // skip directly to the final frame of the animation to avoid running it.
                    //
                    // By calling stop after start, we go to the final frame of the animation.
                    animatable.stop()
                }
            }
        }

        view.isActivated = viewModel.isActivated
        view.drawable.setTint(
            Utils.getColorAttrDefaultColor(
+65 −43
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
import com.android.systemui.statusbar.policy.FlashlightController
import com.android.systemui.utils.leaks.FakeFlashlightController
import com.android.systemui.utils.leaks.LeakCheckedTest
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher
@@ -38,6 +39,7 @@ import org.junit.runners.JUnit4
import org.mockito.Mock
import org.mockito.MockitoAnnotations

@OptIn(ExperimentalCoroutinesApi::class)
@SmallTest
@RunWith(JUnit4::class)
class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() {
@@ -51,7 +53,9 @@ class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() {
        injectLeakCheckedDependency(FlashlightController::class.java)
        MockitoAnnotations.initMocks(this)

        flashlightController = SysuiLeakCheck().getLeakChecker(FlashlightController::class.java) as FakeFlashlightController
        flashlightController =
            SysuiLeakCheck().getLeakChecker(FlashlightController::class.java)
                as FakeFlashlightController
        underTest = FlashlightQuickAffordanceConfig(context, flashlightController)
    }

@@ -69,8 +73,12 @@ class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() {

        // then
        assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
        assertEquals(R.drawable.ic_flashlight_on,
                ((lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).icon as? Icon.Resource)?.res)
        assertEquals(
            R.drawable.qs_flashlight_icon_on,
            ((lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).icon
                    as? Icon.Resource)
                ?.res
        )
        job.cancel()
    }

@@ -88,8 +96,12 @@ class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() {

        // then
        assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
        assertEquals(R.drawable.ic_flashlight_off,
                ((lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).icon as? Icon.Resource)?.res)
        assertEquals(
            R.drawable.qs_flashlight_icon_off,
            ((lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).icon
                    as? Icon.Resource)
                ?.res
        )
        job.cancel()
    }

@@ -107,8 +119,12 @@ class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() {

        // then
        assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
        assertEquals(R.drawable.ic_flashlight_off,
                ((lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).icon as? Icon.Resource)?.res)
        assertEquals(
            R.drawable.qs_flashlight_icon_off,
            ((lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).icon
                    as? Icon.Resource)
                ?.res
        )
        job.cancel()
    }

@@ -143,8 +159,11 @@ class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() {

        // then
        assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
        assertTrue((lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).activationState is ActivationState.Active)
        assertEquals(R.drawable.ic_flashlight_on, (lastValue.icon as? Icon.Resource)?.res)
        assertTrue(
            (lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).activationState
                is ActivationState.Active
        )
        assertEquals(R.drawable.qs_flashlight_icon_on, (lastValue.icon as? Icon.Resource)?.res)
        job.cancel()
    }

@@ -162,8 +181,11 @@ class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() {

        // then
        assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
        assertTrue((lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).activationState is ActivationState.Inactive)
        assertEquals(R.drawable.ic_flashlight_off, (lastValue.icon as? Icon.Resource)?.res)
        assertTrue(
            (lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).activationState
                is ActivationState.Inactive
        )
        assertEquals(R.drawable.qs_flashlight_icon_off, (lastValue.icon as? Icon.Resource)?.res)
        job.cancel()
    }