Merge "Hide resume players on entering the lockdown mode" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
561bd764ba
@@ -42,6 +42,10 @@ class KeyguardTransitionInteractor
|
||||
constructor(
|
||||
repository: KeyguardTransitionRepository,
|
||||
) {
|
||||
/** (any)->GONE transition information */
|
||||
val anyStateToGoneTransition: Flow<TransitionStep> =
|
||||
repository.transitions.filter { step -> step.to == KeyguardState.GONE }
|
||||
|
||||
/** (any)->AOD transition information */
|
||||
val anyStateToAodTransition: Flow<TransitionStep> =
|
||||
repository.transitions.filter { step -> step.to == KeyguardState.AOD }
|
||||
|
||||
@@ -50,6 +50,7 @@ import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import androidx.media.utils.MediaConstants
|
||||
import com.android.internal.logging.InstanceId
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.systemui.Dumpable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
@@ -177,6 +178,7 @@ class MediaDataManager(
|
||||
private val mediaFlags: MediaFlags,
|
||||
private val logger: MediaUiEventLogger,
|
||||
private val smartspaceManager: SmartspaceManager,
|
||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||
) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
|
||||
|
||||
companion object {
|
||||
@@ -241,6 +243,7 @@ class MediaDataManager(
|
||||
mediaFlags: MediaFlags,
|
||||
logger: MediaUiEventLogger,
|
||||
smartspaceManager: SmartspaceManager,
|
||||
keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||
) : this(
|
||||
context,
|
||||
backgroundExecutor,
|
||||
@@ -264,6 +267,7 @@ class MediaDataManager(
|
||||
mediaFlags,
|
||||
logger,
|
||||
smartspaceManager,
|
||||
keyguardUpdateMonitor,
|
||||
)
|
||||
|
||||
private val appChangeReceiver =
|
||||
@@ -1336,7 +1340,9 @@ class MediaDataManager(
|
||||
Assert.isMainThread()
|
||||
val removed = mediaEntries.remove(key) ?: return
|
||||
|
||||
if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) {
|
||||
if (keyguardUpdateMonitor.isUserInLockdown(removed.userId)) {
|
||||
logger.logMediaRemoved(removed.appUid, removed.packageName, removed.instanceId)
|
||||
} else if (useMediaResumption && removed.resumeAction != null && removed.isLocalSession()) {
|
||||
convertToResumePlayer(removed)
|
||||
} else if (mediaFlags.isRetainingPlayersEnabled()) {
|
||||
handlePossibleRemoval(removed, notificationRemoved = true)
|
||||
|
||||
@@ -30,13 +30,20 @@ import android.view.ViewGroup
|
||||
import android.view.animation.PathInterpolator
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.android.internal.logging.InstanceId
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.keyguard.KeyguardUpdateMonitorCallback
|
||||
import com.android.systemui.Dumpable
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.classifier.FalsingCollector
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
import com.android.systemui.lifecycle.repeatWhenAttached
|
||||
import com.android.systemui.media.controls.models.player.MediaData
|
||||
import com.android.systemui.media.controls.models.player.MediaViewHolder
|
||||
import com.android.systemui.media.controls.models.recommendation.RecommendationViewHolder
|
||||
@@ -63,6 +70,10 @@ import java.io.PrintWriter
|
||||
import java.util.TreeMap
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
private const val TAG = "MediaCarouselController"
|
||||
private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS)
|
||||
@@ -91,6 +102,8 @@ constructor(
|
||||
private val logger: MediaUiEventLogger,
|
||||
private val debugLogger: MediaCarouselControllerLogger,
|
||||
private val mediaFlags: MediaFlags,
|
||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
|
||||
) : Dumpable {
|
||||
/** The current width of the carousel */
|
||||
private var currentCarouselWidth: Int = 0
|
||||
@@ -213,6 +226,17 @@ constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private val keyguardUpdateMonitorCallback =
|
||||
object : KeyguardUpdateMonitorCallback() {
|
||||
override fun onStrongAuthStateChanged(userId: Int) {
|
||||
if (keyguardUpdateMonitor.isUserInLockdown(userId)) {
|
||||
hideMediaCarousel()
|
||||
} else if (keyguardUpdateMonitor.isUserUnlocked(userId)) {
|
||||
showMediaCarousel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update MediaCarouselScrollHandler.visibleToUser to reflect media card container visibility.
|
||||
* It will be called when the container is out of view.
|
||||
@@ -487,6 +511,13 @@ constructor(
|
||||
}
|
||||
}
|
||||
)
|
||||
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
|
||||
mediaCarousel.repeatWhenAttached {
|
||||
repeatOnLifecycle(Lifecycle.State.STARTED) {
|
||||
// A backup to show media carousel (if available) once the keyguard is gone.
|
||||
listenForAnyStateToGoneKeyguardTransition(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun inflateSettingsButton() {
|
||||
@@ -516,6 +547,23 @@ constructor(
|
||||
return mediaCarousel
|
||||
}
|
||||
|
||||
private fun hideMediaCarousel() {
|
||||
mediaCarousel.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun showMediaCarousel() {
|
||||
mediaCarousel.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun listenForAnyStateToGoneKeyguardTransition(scope: CoroutineScope): Job {
|
||||
return scope.launch {
|
||||
keyguardTransitionInteractor.anyStateToGoneTransition
|
||||
.filter { it.transitionState == TransitionState.FINISHED }
|
||||
.collect { showMediaCarousel() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun reorderAllPlayers(
|
||||
previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?,
|
||||
key: String? = null
|
||||
|
||||
@@ -40,6 +40,7 @@ import android.testing.TestableLooper.RunWithLooper
|
||||
import androidx.media.utils.MediaConstants
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.internal.logging.InstanceId
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.systemui.InstanceIdSequenceFake
|
||||
import com.android.systemui.R
|
||||
import com.android.systemui.SysuiTestCase
|
||||
@@ -126,6 +127,7 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
@Mock lateinit var pendingIntent: PendingIntent
|
||||
@Mock lateinit var activityStarter: ActivityStarter
|
||||
@Mock lateinit var smartspaceManager: SmartspaceManager
|
||||
@Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
|
||||
lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
|
||||
@Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget
|
||||
@Mock private lateinit var mediaRecommendationItem: SmartspaceAction
|
||||
@@ -187,6 +189,7 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
mediaFlags = mediaFlags,
|
||||
logger = logger,
|
||||
smartspaceManager = smartspaceManager,
|
||||
keyguardUpdateMonitor = keyguardUpdateMonitor
|
||||
)
|
||||
verify(tunerService)
|
||||
.addTunable(capture(tunableCaptor), eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION))
|
||||
@@ -242,6 +245,7 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
whenever(mediaFlags.isRetainingPlayersEnabled()).thenReturn(false)
|
||||
whenever(mediaFlags.isPersistentSsCardEnabled()).thenReturn(false)
|
||||
whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
|
||||
whenever(keyguardUpdateMonitor.isUserInLockdown(any())).thenReturn(false)
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -682,6 +686,19 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
verify(listener).onMediaDataRemoved(eq("0:$PACKAGE_NAME"))
|
||||
}
|
||||
|
||||
fun testOnNotificationRemoved_lockDownMode() {
|
||||
whenever(keyguardUpdateMonitor.isUserInLockdown(any())).thenReturn(true)
|
||||
|
||||
addNotificationAndLoad()
|
||||
val data = mediaDataCaptor.value
|
||||
mediaDataManager.onNotificationRemoved(KEY)
|
||||
|
||||
verify(listener, never()).onMediaDataRemoved(eq(KEY))
|
||||
verify(logger, never())
|
||||
.logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
|
||||
verify(logger).logMediaRemoved(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddResumptionControls() {
|
||||
// WHEN resumption controls are added
|
||||
|
||||
@@ -21,12 +21,20 @@ import android.content.res.Configuration
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.util.MathUtils.abs
|
||||
import android.view.View
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.internal.logging.InstanceId
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.keyguard.KeyguardUpdateMonitorCallback
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.classifier.FalsingCollector
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
import com.android.systemui.dump.DumpManager
|
||||
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
|
||||
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
|
||||
import com.android.systemui.keyguard.shared.model.KeyguardState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionState
|
||||
import com.android.systemui.keyguard.shared.model.TransitionStep
|
||||
import com.android.systemui.media.controls.MediaTestUtils
|
||||
import com.android.systemui.media.controls.models.player.MediaData
|
||||
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData
|
||||
@@ -49,6 +57,9 @@ import javax.inject.Provider
|
||||
import junit.framework.Assert.assertEquals
|
||||
import junit.framework.Assert.assertFalse
|
||||
import junit.framework.Assert.assertTrue
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
@@ -90,11 +101,15 @@ class MediaCarouselControllerTest : SysuiTestCase() {
|
||||
@Mock lateinit var mediaCarousel: MediaScrollView
|
||||
@Mock lateinit var pageIndicator: PageIndicator
|
||||
@Mock lateinit var mediaFlags: MediaFlags
|
||||
@Mock lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
|
||||
@Mock lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
|
||||
private lateinit var transitionRepository: FakeKeyguardTransitionRepository
|
||||
@Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
|
||||
@Captor
|
||||
lateinit var configListener: ArgumentCaptor<ConfigurationController.ConfigurationListener>
|
||||
@Captor lateinit var newConfig: ArgumentCaptor<Configuration>
|
||||
@Captor lateinit var visualStabilityCallback: ArgumentCaptor<OnReorderingAllowedListener>
|
||||
@Captor lateinit var keyguardCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
|
||||
|
||||
private val clock = FakeSystemClock()
|
||||
private lateinit var mediaCarouselController: MediaCarouselController
|
||||
@@ -102,6 +117,7 @@ class MediaCarouselControllerTest : SysuiTestCase() {
|
||||
@Before
|
||||
fun setup() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
transitionRepository = FakeKeyguardTransitionRepository()
|
||||
mediaCarouselController =
|
||||
MediaCarouselController(
|
||||
context,
|
||||
@@ -119,11 +135,14 @@ class MediaCarouselControllerTest : SysuiTestCase() {
|
||||
logger,
|
||||
debugLogger,
|
||||
mediaFlags,
|
||||
keyguardUpdateMonitor,
|
||||
KeyguardTransitionInteractor(repository = transitionRepository),
|
||||
)
|
||||
verify(configurationController).addCallback(capture(configListener))
|
||||
verify(mediaDataManager).addListener(capture(listener))
|
||||
verify(visualStabilityProvider)
|
||||
.addPersistentReorderingAllowedListener(capture(visualStabilityCallback))
|
||||
verify(keyguardUpdateMonitor).registerCallback(capture(keyguardCallback))
|
||||
whenever(mediaControlPanelFactory.get()).thenReturn(panel)
|
||||
whenever(panel.mediaViewController).thenReturn(mediaViewController)
|
||||
whenever(mediaDataManager.smartspaceMediaData).thenReturn(smartspaceMediaData)
|
||||
@@ -740,4 +759,41 @@ class MediaCarouselControllerTest : SysuiTestCase() {
|
||||
assertTrue(MediaPlayerData.visiblePlayerKeys().elementAt(0).isSsMediaRec)
|
||||
assertFalse(MediaPlayerData.visiblePlayerKeys().elementAt(0).data.active)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testOnLockDownMode_hideMediaCarousel() {
|
||||
whenever(keyguardUpdateMonitor.isUserInLockdown(context.userId)).thenReturn(true)
|
||||
mediaCarouselController.mediaCarousel = mediaCarousel
|
||||
|
||||
keyguardCallback.value.onStrongAuthStateChanged(context.userId)
|
||||
|
||||
verify(mediaCarousel).visibility = View.GONE
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLockDownModeOff_showMediaCarousel() {
|
||||
whenever(keyguardUpdateMonitor.isUserInLockdown(context.userId)).thenReturn(false)
|
||||
whenever(keyguardUpdateMonitor.isUserUnlocked(context.userId)).thenReturn(true)
|
||||
mediaCarouselController.mediaCarousel = mediaCarousel
|
||||
|
||||
keyguardCallback.value.onStrongAuthStateChanged(context.userId)
|
||||
|
||||
verify(mediaCarousel).visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
@Test
|
||||
fun testKeyguardGone_showMediaCarousel() =
|
||||
runTest(UnconfinedTestDispatcher()) {
|
||||
mediaCarouselController.mediaCarousel = mediaCarousel
|
||||
|
||||
val job = mediaCarouselController.listenForAnyStateToGoneKeyguardTransition(this)
|
||||
transitionRepository.sendTransitionStep(
|
||||
TransitionStep(to = KeyguardState.GONE, transitionState = TransitionState.FINISHED)
|
||||
)
|
||||
|
||||
verify(mediaCarousel).visibility = View.VISIBLE
|
||||
|
||||
job.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user