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

Commit 910d0090 authored by Christian Göllner's avatar Christian Göllner Committed by Android (Google) Code Review
Browse files

Merge "[Split shade] Fix QS actions footer border visible on shade expansion" into tm-qpr-dev

parents 6ac23a11 d6a6294f
Loading
Loading
Loading
Loading
+49 −8
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.qs

import android.content.Intent
import android.content.res.Configuration
import android.os.Handler
import android.os.UserManager
import android.provider.Settings
@@ -38,9 +39,11 @@ import com.android.systemui.qs.dagger.QSFlagsModule.PM_LITE_ENABLED
import com.android.systemui.qs.dagger.QSScope
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.MultiUserSwitchController
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.statusbar.policy.UserInfoController
import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener
import com.android.systemui.util.LargeScreenUtils
import com.android.systemui.util.ViewController
import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
@@ -69,18 +72,43 @@ internal class FooterActionsController @Inject constructor(
    private val uiEventLogger: UiEventLogger,
    @Named(PM_LITE_ENABLED) private val showPMLiteButton: Boolean,
    private val globalSetting: GlobalSettings,
    private val handler: Handler
    private val handler: Handler,
    private val configurationController: ConfigurationController,
) : ViewController<FooterActionsView>(view) {

    private var globalActionsDialog: GlobalActionsDialogLite? = null

    private var lastExpansion = -1f
    private var listening: Boolean = false
    private var inSplitShade = false

    private val alphaAnimator = TouchAnimator.Builder()
            .addFloat(mView, "alpha", 0f, 1f)
    private val singleShadeAnimator by lazy {
        // In single shade, the actions footer should only appear at the end of the expansion,
        // so that it doesn't overlap with the notifications panel.
        TouchAnimator.Builder().addFloat(mView, "alpha", 0f, 1f).setStartDelay(0.9f).build()
    }

    private val splitShadeAnimator by lazy {
        // The Actions footer view has its own background which is the same color as the qs panel's
        // background.
        // We don't want it to fade in at the same time as the rest of the panel, otherwise it is
        // more opaque than the rest of the panel's background. Only applies to split shade.
        val alphaAnimator = TouchAnimator.Builder().addFloat(mView, "alpha", 0f, 1f).build()
        val bgAlphaAnimator =
            TouchAnimator.Builder()
                .addFloat(mView, "backgroundAlpha", 0f, 1f)
                .setStartDelay(0.9f)
                .build()
        // In split shade, we want the actions footer to fade in exactly at the same time as the
        // rest of the shade, as there is no overlap.
        TouchAnimator.Builder()
            .addFloat(alphaAnimator, "position", 0f, 1f)
            .addFloat(bgAlphaAnimator, "position", 0f, 1f)
            .build()
    }

    private val animators: TouchAnimator
        get() = if (inSplitShade) splitShadeAnimator else singleShadeAnimator

    var visible = true
        set(value) {
@@ -95,9 +123,7 @@ internal class FooterActionsController @Inject constructor(
    private val multiUserSwitchController = multiUserSwitchControllerFactory.create(view)

    @VisibleForTesting
    internal val securityFootersSeparator = View(context).apply {
        visibility = View.GONE
    }
    internal val securityFootersSeparator = View(context).apply { visibility = View.GONE }

    private val onUserInfoChangedListener = OnUserInfoChangedListener { _, picture, _ ->
        val isGuestUser: Boolean = userManager.isGuestUser(KeyguardUpdateMonitor.getCurrentUser())
@@ -133,6 +159,17 @@ internal class FooterActionsController @Inject constructor(
        }
    }

    private val configurationListener =
        object : ConfigurationController.ConfigurationListener {
            override fun onConfigChanged(newConfig: Configuration?) {
                updateResources()
            }
        }

    private fun updateResources() {
        inSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(resources)
    }

    override fun onInit() {
        multiUserSwitchController.init()
        securityFooterController.init()
@@ -189,6 +226,9 @@ internal class FooterActionsController @Inject constructor(
        securityFooterController.setOnVisibilityChangedListener(visibilityListener)
        fgsManagerFooterController.setOnVisibilityChangedListener(visibilityListener)

        configurationController.addCallback(configurationListener)

        updateResources()
        updateView()
    }

@@ -201,6 +241,7 @@ internal class FooterActionsController @Inject constructor(
        globalActionsDialog = null
        setListening(false)
        multiUserSetting.isListening = false
        configurationController.removeCallback(configurationListener)
    }

    fun setListening(listening: Boolean) {
@@ -224,7 +265,7 @@ internal class FooterActionsController @Inject constructor(
    }

    fun setExpansion(headerExpansionFraction: Float) {
        alphaAnimator.setPosition(headerExpansionFraction)
        animators.setPosition(headerExpansionFraction)
    }

    fun setKeyguardShowing(showing: Boolean) {
+15 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.view.MotionEvent
import android.view.View
import android.widget.ImageView
import android.widget.LinearLayout
import androidx.annotation.Keep
import com.android.settingslib.Utils
import com.android.settingslib.drawable.UserIconDrawable
import com.android.systemui.R
@@ -45,6 +46,19 @@ class FooterActionsView(context: Context?, attrs: AttributeSet?) : LinearLayout(
    private var qsDisabled = false
    private var expansionAmount = 0f

    /**
     * Sets the alpha of the background of this view.
     *
     * Used from a [TouchAnimator] in the controller.
     */
    var backgroundAlpha: Float = 1f
        @Keep
        set(value) {
            field = value
            background?.alpha = (value * 255).toInt()
        }
        @Keep get

    override fun onFinishInflate() {
        super.onFinishInflate()
        settingsContainer = findViewById(R.id.settings_button_container)
+5 −3
Original line number Diff line number Diff line
@@ -557,9 +557,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
    public void setQsExpansion(float expansion, float panelExpansionFraction,
            float proposedTranslation, float squishinessFraction) {
        float headerTranslation = mTransitioningToFullShade ? 0 : proposedTranslation;
        float progress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD
        float alphaProgress = mTransitioningToFullShade || mState == StatusBarState.KEYGUARD
                ? mFullShadeProgress : panelExpansionFraction;
        setAlphaAnimationProgress(mInSplitShade ? progress : 1);
        setAlphaAnimationProgress(mInSplitShade ? alphaProgress : 1);
        mContainer.setExpansion(expansion);
        final float translationScaleY = (mInSplitShade
                ? 1 : QSAnimator.SHORT_PARALLAX_AMOUNT) * (expansion - 1);
@@ -600,7 +600,9 @@ public class QSFragment extends LifecycleFragment implements QS, CommandQueue.Ca
        }
        mQSPanelController.setIsOnKeyguard(onKeyguard);
        mFooter.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
        mQSFooterActionController.setExpansion(onKeyguardAndExpanded ? 1 : expansion);
        float footerActionsExpansion =
                onKeyguardAndExpanded ? 1 : mInSplitShade ? alphaProgress : expansion;
        mQSFooterActionController.setExpansion(footerActionsExpansion);
        mQSPanelController.setRevealExpansion(expansion);
        mQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
        mQuickQSPanelController.getTileLayout().setExpansion(expansion, proposedTranslation);
+152 −37
Original line number Diff line number Diff line
@@ -22,13 +22,17 @@ import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.settings.UserTracker
import com.android.systemui.statusbar.phone.MultiUserSwitchController
import com.android.systemui.statusbar.policy.DeviceProvisionedController
import com.android.systemui.statusbar.policy.FakeConfigurationController
import com.android.systemui.statusbar.policy.UserInfoController
import com.android.systemui.util.mockito.capture
import com.android.systemui.util.settings.FakeSettings
import com.android.systemui.utils.leaks.LeakCheckedTest
import com.google.common.truth.Expect
import com.google.common.truth.Truth.assertThat
import javax.inject.Provider
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
@@ -42,47 +46,38 @@ import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
import javax.inject.Provider
import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations

@SmallTest
@TestableLooper.RunWithLooper(setAsMainLooper = true)
@RunWith(AndroidTestingRunner::class)
class FooterActionsControllerTest : LeakCheckedTest() {
    @Mock
    private lateinit var userManager: UserManager
    @Mock
    private lateinit var userTracker: UserTracker
    @Mock
    private lateinit var activityStarter: ActivityStarter
    @Mock
    private lateinit var deviceProvisionedController: DeviceProvisionedController
    @Mock
    private lateinit var userInfoController: UserInfoController
    @Mock
    private lateinit var multiUserSwitchControllerFactory: MultiUserSwitchController.Factory
    @Mock
    private lateinit var multiUserSwitchController: MultiUserSwitchController
    @Mock
    private lateinit var globalActionsDialogProvider: Provider<GlobalActionsDialogLite>
    @Mock
    private lateinit var globalActionsDialog: GlobalActionsDialogLite
    @Mock
    private lateinit var uiEventLogger: UiEventLogger
    @Mock
    private lateinit var securityFooterController: QSSecurityFooter
    @Mock
    private lateinit var fgsManagerController: QSFgsManagerFooter

    @get:Rule var expect: Expect = Expect.create()

    @Mock private lateinit var userManager: UserManager
    @Mock private lateinit var userTracker: UserTracker
    @Mock private lateinit var activityStarter: ActivityStarter
    @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
    @Mock private lateinit var userInfoController: UserInfoController
    @Mock private lateinit var multiUserSwitchControllerFactory: MultiUserSwitchController.Factory
    @Mock private lateinit var multiUserSwitchController: MultiUserSwitchController
    @Mock private lateinit var globalActionsDialogProvider: Provider<GlobalActionsDialogLite>
    @Mock private lateinit var globalActionsDialog: GlobalActionsDialogLite
    @Mock private lateinit var uiEventLogger: UiEventLogger
    @Mock private lateinit var securityFooterController: QSSecurityFooter
    @Mock private lateinit var fgsManagerController: QSFgsManagerFooter
    @Captor
    private lateinit var visibilityChangedCaptor:
        ArgumentCaptor<VisibilityChangedDispatcher.OnVisibilityChangedListener>

    private lateinit var controller: FooterActionsController

    private val configurationController = FakeConfigurationController()
    private val metricsLogger: MetricsLogger = FakeMetricsLogger()
    private lateinit var view: FooterActionsView
    private val falsingManager: FalsingManagerFake = FalsingManagerFake()
    private lateinit var view: FooterActionsView
    private lateinit var testableLooper: TestableLooper
    private lateinit var fakeSettings: FakeSettings
    private lateinit var securityFooter: View
@@ -90,6 +85,9 @@ class FooterActionsControllerTest : LeakCheckedTest() {

    @Before
    fun setUp() {
        // We want to make sure testable resources are always used
        context.ensureTestableResources()

        MockitoAnnotations.initMocks(this)
        testableLooper = TestableLooper.get(this)
        fakeSettings = FakeSettings()
@@ -299,6 +297,86 @@ class FooterActionsControllerTest : LeakCheckedTest() {
        assertThat(booleanCaptor.allValues.last()).isTrue()
    }

    @Test
    fun setExpansion_inSplitShade_alphaFollowsExpansion() {
        enableSplitShade()

        controller.setExpansion(0f)
        expect.that(view.alpha).isEqualTo(0f)

        controller.setExpansion(0.25f)
        expect.that(view.alpha).isEqualTo(0.25f)

        controller.setExpansion(0.5f)
        expect.that(view.alpha).isEqualTo(0.5f)

        controller.setExpansion(0.75f)
        expect.that(view.alpha).isEqualTo(0.75f)

        controller.setExpansion(1f)
        expect.that(view.alpha).isEqualTo(1f)
    }

    @Test
    fun setExpansion_inSplitShade_backgroundAlphaFollowsExpansion_with_0_9_delay() {
        enableSplitShade()

        controller.setExpansion(0f)
        expect.that(view.backgroundAlphaFraction).isEqualTo(0f)

        controller.setExpansion(0.5f)
        expect.that(view.backgroundAlphaFraction).isEqualTo(0f)

        controller.setExpansion(0.9f)
        expect.that(view.backgroundAlphaFraction).isEqualTo(0f)

        controller.setExpansion(0.91f)
        expect.that(view.backgroundAlphaFraction).isWithin(FLOAT_TOLERANCE).of(0.1f)

        controller.setExpansion(0.95f)
        expect.that(view.backgroundAlphaFraction).isWithin(FLOAT_TOLERANCE).of(0.5f)

        controller.setExpansion(1f)
        expect.that(view.backgroundAlphaFraction).isEqualTo(1f)
    }

    @Test
    fun setExpansion_inSingleShade_alphaFollowsExpansion_with_0_9_delay() {
        disableSplitShade()

        controller.setExpansion(0f)
        expect.that(view.alpha).isEqualTo(0f)

        controller.setExpansion(0.5f)
        expect.that(view.alpha).isEqualTo(0f)

        controller.setExpansion(0.9f)
        expect.that(view.alpha).isEqualTo(0f)

        controller.setExpansion(0.91f)
        expect.that(view.alpha).isWithin(FLOAT_TOLERANCE).of(0.1f)

        controller.setExpansion(0.95f)
        expect.that(view.alpha).isWithin(FLOAT_TOLERANCE).of(0.5f)

        controller.setExpansion(1f)
        expect.that(view.alpha).isEqualTo(1f)
    }

    @Test
    fun setExpansion_inSingleShade_backgroundAlphaAlways1() {
        disableSplitShade()

        controller.setExpansion(0f)
        expect.that(view.backgroundAlphaFraction).isEqualTo(1f)

        controller.setExpansion(0.5f)
        expect.that(view.backgroundAlphaFraction).isEqualTo(1f)

        controller.setExpansion(1f)
        expect.that(view.backgroundAlphaFraction).isEqualTo(1f)
    }

    private fun setVisibilities(
        securityFooterVisible: Boolean,
        fgsFooterVisible: Boolean,
@@ -311,15 +389,52 @@ class FooterActionsControllerTest : LeakCheckedTest() {
    }

    private fun inflateView(): FooterActionsView {
        return LayoutInflater.from(context)
                .inflate(R.layout.footer_actions, null) as FooterActionsView
        return LayoutInflater.from(context).inflate(R.layout.footer_actions, null)
            as FooterActionsView
    }

    private fun constructFooterActionsController(view: FooterActionsView): FooterActionsController {
        return FooterActionsController(view, multiUserSwitchControllerFactory,
                activityStarter, userManager, userTracker, userInfoController,
                deviceProvisionedController, securityFooterController, fgsManagerController,
                falsingManager, metricsLogger, globalActionsDialogProvider, uiEventLogger,
                showPMLiteButton = true, fakeSettings, Handler(testableLooper.looper))
        return FooterActionsController(
            view,
            multiUserSwitchControllerFactory,
            activityStarter,
            userManager,
            userTracker,
            userInfoController,
            deviceProvisionedController,
            securityFooterController,
            fgsManagerController,
            falsingManager,
            metricsLogger,
            globalActionsDialogProvider,
            uiEventLogger,
            showPMLiteButton = true,
            fakeSettings,
            Handler(testableLooper.looper),
            configurationController)
    }

    private fun enableSplitShade() {
        setSplitShadeEnabled(true)
    }

    private fun disableSplitShade() {
        setSplitShadeEnabled(false)
    }

    private fun setSplitShadeEnabled(enabled: Boolean) {
        overrideResource(R.bool.config_use_split_notification_shade, enabled)
        configurationController.notifyConfigurationChanged()
    }
}

private const val FLOAT_TOLERANCE = 0.01f

private val View.backgroundAlphaFraction: Float?
    get() {
        return if (background != null) {
            background.alpha / 255f
        } else {
            null
        }
    }
+34 −0
Original line number Diff line number Diff line
@@ -204,6 +204,40 @@ public class QSFragmentTest extends SysuiBaseFragmentTest {
        assertThat(mQsFragmentView.getAlpha()).isEqualTo(1);
    }

    @Test
    public void setQsExpansion_inSplitShade_setsFooterActionsExpansion_basedOnPanelExpFraction() {
        // Random test values without any meaning. They just have to be different from each other.
        float expansion = 0.123f;
        float panelExpansionFraction = 0.321f;
        float proposedTranslation = 456f;
        float squishinessFraction = 0.987f;

        QSFragment fragment = resumeAndGetFragment();
        enableSplitShade();

        fragment.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation,
                squishinessFraction);

        verify(mQSFooterActionController).setExpansion(panelExpansionFraction);
    }

    @Test
    public void setQsExpansion_notInSplitShade_setsFooterActionsExpansion_basedOnExpansion() {
        // Random test values without any meaning. They just have to be different from each other.
        float expansion = 0.123f;
        float panelExpansionFraction = 0.321f;
        float proposedTranslation = 456f;
        float squishinessFraction = 0.987f;

        QSFragment fragment = resumeAndGetFragment();
        disableSplitShade();

        fragment.setQsExpansion(expansion, panelExpansionFraction, proposedTranslation,
                squishinessFraction);

        verify(mQSFooterActionController).setExpansion(expansion);
    }

    @Test
    public void getQsMinExpansionHeight_notInSplitShade_returnsHeaderHeight() {
        QSFragment fragment = resumeAndGetFragment();