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

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

Merge "Fix media staying too long during shade "immediate" expansion/collapsing" into tm-qpr-dev

parents b90801bb b0f2e4b5
Loading
Loading
Loading
Loading
+29 −2
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dreams.DreamOverlayStateController
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.NotifPanelEvents
import com.android.systemui.statusbar.CrossFadeHelper
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
@@ -85,12 +86,21 @@ class MediaHierarchyManager @Inject constructor(
    private val bypassController: KeyguardBypassController,
    private val mediaCarouselController: MediaCarouselController,
    private val notifLockscreenUserManager: NotificationLockscreenUserManager,
    private val keyguardViewController: KeyguardViewController,
    private val dreamOverlayStateController: DreamOverlayStateController,
    configurationController: ConfigurationController,
    wakefulnessLifecycle: WakefulnessLifecycle,
    private val keyguardViewController: KeyguardViewController,
    private val dreamOverlayStateController: DreamOverlayStateController
    panelEventsEvents: NotifPanelEvents,
) {

    /**
     * Whether we "skip" QQS during panel expansion.
     *
     * This means that when expanding the panel we go directly to QS. Also when we are on QS and
     * start closing the panel, it fully collapses instead of going to QQS.
     */
    private var skipQqsOnExpansion: Boolean = false

    /**
     * The root overlay of the hierarchy. This is where the media notification is attached to
     * whenever the view is transitioning from one host to another. It also make sure that the
@@ -504,6 +514,13 @@ class MediaHierarchyManager @Inject constructor(
        mediaCarouselController.updateUserVisibility = {
            mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
        }

        panelEventsEvents.registerListener(object : NotifPanelEvents.Listener {
            override fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {
                skipQqsOnExpansion = isExpandImmediateEnabled
                updateDesiredLocation()
            }
        })
    }

    private fun updateConfiguration() {
@@ -701,6 +718,9 @@ class MediaHierarchyManager @Inject constructor(
        if (isCurrentlyInGuidedTransformation()) {
            return false
        }
        if (skipQqsOnExpansion) {
            return false
        }
        // This is an invalid transition, and can happen when using the camera gesture from the
        // lock screen. Disallow.
        if (previousLocation == LOCATION_LOCKSCREEN &&
@@ -852,6 +872,9 @@ class MediaHierarchyManager @Inject constructor(
     * otherwise
     */
    private fun getTransformationProgress(): Float {
        if (skipQqsOnExpansion) {
            return -1.0f
        }
        val progress = getQSTransformationProgress()
        if (statusbarState != StatusBarState.KEYGUARD && progress >= 0) {
            return progress
@@ -1042,6 +1065,10 @@ class MediaHierarchyManager @Inject constructor(
            // reattach it without an animation
            return LOCATION_LOCKSCREEN
        }
        if (skipQqsOnExpansion) {
            // When doing an immediate expand or collapse, we want to keep it in QS.
            return LOCATION_QS
        }
        return location
    }

+16 −2
Original line number Diff line number Diff line
@@ -29,11 +29,25 @@ interface NotifPanelEvents {
    interface Listener {

        /** Invoked when the notification panel starts or stops collapsing. */
        fun onPanelCollapsingChanged(isCollapsing: Boolean)
        @JvmDefault
        fun onPanelCollapsingChanged(isCollapsing: Boolean) {}

        /**
         * Invoked when the notification panel starts or stops launching an [android.app.Activity].
         */
        fun onLaunchingActivityChanged(isLaunchingActivity: Boolean)
        @JvmDefault
        fun onLaunchingActivityChanged(isLaunchingActivity: Boolean) {}

        /**
         * Invoked when the "expand immediate" attribute changes.
         *
         * An example of expanding immediately is when swiping down from the top with two fingers.
         * Instead of going to QQS, we immediately expand to full QS.
         *
         * Another example is when full QS is showing, and we swipe up from the bottom. Instead of
         * going to QQS, the panel fully collapses.
         */
        @JvmDefault
        fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {}
    }
}
+17 −6
Original line number Diff line number Diff line
@@ -1745,12 +1745,17 @@ public final class NotificationPanelViewController extends PanelViewController {
        }

        if (mQsExpanded) {
            mQsExpandImmediate = true;
            setQsExpandImmediate(true);
            setShowShelfOnly(true);
        }
        super.collapse(delayed, speedUpFactor);
    }

    private void setQsExpandImmediate(boolean expandImmediate) {
        mQsExpandImmediate = expandImmediate;
        mPanelEventsEmitter.notifyExpandImmediateChange(expandImmediate);
    }

    private void setShowShelfOnly(boolean shelfOnly) {
        mNotificationStackScrollLayoutController.setShouldShowShelfOnly(
                shelfOnly && !mSplitShadeEnabled);
@@ -1803,7 +1808,7 @@ public final class NotificationPanelViewController extends PanelViewController {

    public void expandWithQs() {
        if (isQsExpansionEnabled()) {
            mQsExpandImmediate = true;
            setQsExpandImmediate(true);
            setShowShelfOnly(true);
        }
        if (mSplitShadeEnabled && isOnKeyguard()) {
@@ -2132,7 +2137,7 @@ public final class NotificationPanelViewController extends PanelViewController {
        if (mTwoFingerQsExpandPossible && isOpenQsEvent(event) && event.getY(event.getActionIndex())
                < mStatusBarMinHeight) {
            mMetricsLogger.count(COUNTER_PANEL_OPEN_QS, 1);
            mQsExpandImmediate = true;
            setQsExpandImmediate(true);
            setShowShelfOnly(true);
            requestPanelHeightUpdate();

@@ -3334,7 +3339,7 @@ public final class NotificationPanelViewController extends PanelViewController {
        } else {
            setListening(true);
        }
        mQsExpandImmediate = false;
        setQsExpandImmediate(false);
        setShowShelfOnly(false);
        mTwoFingerQsExpandPossible = false;
        updateTrackingHeadsUp(null);
@@ -3392,7 +3397,7 @@ public final class NotificationPanelViewController extends PanelViewController {
        super.onTrackingStarted();
        mScrimController.onTrackingStarted();
        if (mQsFullyExpanded) {
            mQsExpandImmediate = true;
            setQsExpandImmediate(true);
            setShowShelfOnly(true);
        }
        mNotificationStackScrollLayoutController.onPanelTrackingStarted();
@@ -4959,7 +4964,7 @@ public final class NotificationPanelViewController extends PanelViewController {
            // to locked will trigger this event and we're not actually in the process of opening
            // the shade, lockscreen is just always expanded
            if (mSplitShadeEnabled && !isOnKeyguard()) {
                mQsExpandImmediate = true;
                setQsExpandImmediate(true);
            }
            mCentralSurfaces.makeExpandedVisible(false);
        }
@@ -5026,5 +5031,11 @@ public final class NotificationPanelViewController extends PanelViewController {
                cb.onPanelCollapsingChanged(isCollapsing);
            }
        }

        private void notifyExpandImmediateChange(boolean expandImmediateEnabled) {
            for (NotifPanelEvents.Listener cb : mListeners) {
                cb.onExpandImmediateChanged(expandImmediateEnabled);
            }
        }
    }
}
+52 −30
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.media

import org.mockito.Mockito.`when` as whenever
import android.graphics.Rect
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
@@ -30,6 +29,7 @@ import com.android.systemui.controls.controller.ControlsControllerImplTest.Compa
import com.android.systemui.dreams.DreamOverlayStateController
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.shade.testing.FakeNotifPanelEvents
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -50,10 +50,11 @@ import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.`when`
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when`
import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit

@SmallTest
@@ -61,32 +62,19 @@ import org.mockito.junit.MockitoJUnit
@TestableLooper.RunWithLooper
class MediaHierarchyManagerTest : SysuiTestCase() {

    @Mock
    private lateinit var lockHost: MediaHost
    @Mock
    private lateinit var qsHost: MediaHost
    @Mock
    private lateinit var qqsHost: MediaHost
    @Mock
    private lateinit var bypassController: KeyguardBypassController
    @Mock
    private lateinit var keyguardStateController: KeyguardStateController
    @Mock
    private lateinit var statusBarStateController: SysuiStatusBarStateController
    @Mock
    private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
    @Mock
    private lateinit var mediaCarouselController: MediaCarouselController
    @Mock
    private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
    @Mock
    private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
    @Mock
    private lateinit var keyguardViewController: KeyguardViewController
    @Mock
    private lateinit var uniqueObjectHostView: UniqueObjectHostView
    @Mock
    private lateinit var dreamOverlayStateController: DreamOverlayStateController
    @Mock private lateinit var lockHost: MediaHost
    @Mock private lateinit var qsHost: MediaHost
    @Mock private lateinit var qqsHost: MediaHost
    @Mock private lateinit var bypassController: KeyguardBypassController
    @Mock private lateinit var keyguardStateController: KeyguardStateController
    @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
    @Mock private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
    @Mock private lateinit var mediaCarouselController: MediaCarouselController
    @Mock private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
    @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
    @Mock private lateinit var keyguardViewController: KeyguardViewController
    @Mock private lateinit var uniqueObjectHostView: UniqueObjectHostView
    @Mock private lateinit var dreamOverlayStateController: DreamOverlayStateController
    @Captor
    private lateinit var wakefullnessObserver: ArgumentCaptor<(WakefulnessLifecycle.Observer)>
    @Captor
@@ -97,6 +85,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
    private lateinit var mediaHiearchyManager: MediaHierarchyManager
    private lateinit var mediaFrame: ViewGroup
    private val configurationController = FakeConfigurationController()
    private val notifPanelEvents = FakeNotifPanelEvents()

    @Before
    fun setup() {
@@ -111,10 +100,12 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
                bypassController,
                mediaCarouselController,
                notificationLockscreenUserManager,
                keyguardViewController,
                dreamOverlayStateController,
                configurationController,
                wakefulnessLifecycle,
                keyguardViewController,
                dreamOverlayStateController)
                notifPanelEvents,
        )
        verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
        verify(statusBarStateController).addCallback(statusBarCallback.capture())
        setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
@@ -211,6 +202,25 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
        assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
    }

    @Test
    fun calculateTransformationType_notOnLockscreen_returnsTransition() {
        expandQS()

        val transformType = mediaHiearchyManager.calculateTransformationType()

        assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION)
    }

    @Test
    fun calculateTransformationType_onLockscreen_returnsTransition() {
        goToLockscreen()
        expandQS()

        val transformType = mediaHiearchyManager.calculateTransformationType()

        assertThat(transformType).isEqualTo(MediaHierarchyManager.TRANSFORMATION_TYPE_FADE)
    }

    @Test
    fun calculateTransformationType_onLockShade_inSplitShade_goingToFullShade_returnsTransition() {
        enableSplitShade()
@@ -294,6 +304,18 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
        assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isTrue()
    }

    @Test
    fun isCurrentlyInGuidedTransformation_hostsVisible_expandImmediateEnabled_returnsFalse() {
        notifPanelEvents.changeExpandImmediate(expandImmediate = true)
        goToLockscreen()
        enterGuidedTransformation()
        whenever(lockHost.visible).thenReturn(true)
        whenever(qsHost.visible).thenReturn(true)
        whenever(qqsHost.visible).thenReturn(true)

        assertThat(mediaHiearchyManager.isCurrentlyInGuidedTransformation()).isFalse()
    }

    @Test
    fun isCurrentlyInGuidedTransformation_hostNotVisible_returnsTrue() {
        goToLockscreen()
+37 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.shade.testing

import com.android.systemui.shade.NotifPanelEvents

/** Fake implementation of [NotifPanelEvents] for testing. */
class FakeNotifPanelEvents : NotifPanelEvents {

    private val listeners = mutableListOf<NotifPanelEvents.Listener>()

    override fun registerListener(listener: NotifPanelEvents.Listener) {
        listeners.add(listener)
    }

    override fun unregisterListener(listener: NotifPanelEvents.Listener) {
        listeners.remove(listener)
    }

    fun changeExpandImmediate(expandImmediate: Boolean) {
        listeners.forEach { it.onExpandImmediateChanged(expandImmediate) }
    }
}