Merge "Fixed an issue where the keyguard media visibility was wrong" into sc-dev
This commit is contained in:
@@ -16,16 +16,22 @@
|
||||
|
||||
package com.android.systemui.media
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.media.dagger.MediaModule.KEYGUARD
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController
|
||||
import com.android.systemui.statusbar.FeatureFlags
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.SysuiStatusBarStateController
|
||||
import com.android.systemui.statusbar.notification.stack.MediaHeaderView
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||
import com.android.systemui.util.Utils
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Named
|
||||
|
||||
@@ -38,7 +44,10 @@ class KeyguardMediaController @Inject constructor(
|
||||
@param:Named(KEYGUARD) private val mediaHost: MediaHost,
|
||||
private val bypassController: KeyguardBypassController,
|
||||
private val statusBarStateController: SysuiStatusBarStateController,
|
||||
private val notifLockscreenUserManager: NotificationLockscreenUserManager
|
||||
private val notifLockscreenUserManager: NotificationLockscreenUserManager,
|
||||
private val featureFlags: FeatureFlags,
|
||||
private val context: Context,
|
||||
configurationController: ConfigurationController
|
||||
) {
|
||||
|
||||
init {
|
||||
@@ -46,12 +55,10 @@ class KeyguardMediaController @Inject constructor(
|
||||
override fun onStateChanged(newState: Int) {
|
||||
refreshMediaPosition()
|
||||
}
|
||||
|
||||
override fun onDozingChanged(isDozing: Boolean) {
|
||||
if (!isDozing) {
|
||||
mediaHost.visible = true
|
||||
refreshMediaPosition()
|
||||
}
|
||||
})
|
||||
configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
|
||||
override fun onConfigChanged(newConfig: Configuration?) {
|
||||
updateResources()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -62,8 +69,24 @@ class KeyguardMediaController @Inject constructor(
|
||||
|
||||
// Let's now initialize this view, which also creates the host view for us.
|
||||
mediaHost.init(MediaHierarchyManager.LOCATION_LOCKSCREEN)
|
||||
updateResources()
|
||||
}
|
||||
|
||||
private fun updateResources() {
|
||||
useSplitShade = Utils.shouldUseSplitNotificationShade(featureFlags, context.resources)
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
var useSplitShade = false
|
||||
set(value) {
|
||||
if (field == value) {
|
||||
return
|
||||
}
|
||||
field = value
|
||||
reattachHostView()
|
||||
refreshMediaPosition()
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the media player visible?
|
||||
*/
|
||||
@@ -78,34 +101,63 @@ class KeyguardMediaController @Inject constructor(
|
||||
var singlePaneContainer: MediaHeaderView? = null
|
||||
private set
|
||||
private var splitShadeContainer: ViewGroup? = null
|
||||
private var useSplitShadeContainer: () -> Boolean = { false }
|
||||
|
||||
/**
|
||||
* Attaches media container in single pane mode, situated at the top of the notifications list
|
||||
*/
|
||||
fun attachSinglePaneContainer(mediaView: MediaHeaderView?) {
|
||||
val needsListener = singlePaneContainer == null
|
||||
singlePaneContainer = mediaView
|
||||
if (needsListener) {
|
||||
// On reinflation we don't want to add another listener
|
||||
mediaHost.addVisibilityChangeListener(this::onMediaHostVisibilityChanged)
|
||||
}
|
||||
reattachHostView()
|
||||
onMediaHostVisibilityChanged(mediaHost.visible)
|
||||
}
|
||||
|
||||
// Required to show it for the first time, afterwards visibility is managed automatically
|
||||
mediaHost.visible = true
|
||||
mediaHost.addVisibilityChangeListener { visible ->
|
||||
refreshMediaPosition()
|
||||
if (visible) {
|
||||
mediaHost.hostView.layoutParams.apply {
|
||||
height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
}
|
||||
/**
|
||||
* Called whenever the media hosts visibility changes
|
||||
*/
|
||||
private fun onMediaHostVisibilityChanged(visible: Boolean) {
|
||||
refreshMediaPosition()
|
||||
if (visible) {
|
||||
mediaHost.hostView.layoutParams.apply {
|
||||
height = ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
width = ViewGroup.LayoutParams.MATCH_PARENT
|
||||
}
|
||||
}
|
||||
refreshMediaPosition()
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches media container in split shade mode, situated to the left of notifications
|
||||
*/
|
||||
fun attachSplitShadeContainer(container: ViewGroup, useContainer: () -> Boolean) {
|
||||
fun attachSplitShadeContainer(container: ViewGroup) {
|
||||
splitShadeContainer = container
|
||||
useSplitShadeContainer = useContainer
|
||||
reattachHostView()
|
||||
refreshMediaPosition()
|
||||
}
|
||||
|
||||
private fun reattachHostView() {
|
||||
val inactiveContainer: ViewGroup?
|
||||
val activeContainer: ViewGroup?
|
||||
if (useSplitShade) {
|
||||
activeContainer = splitShadeContainer
|
||||
inactiveContainer = singlePaneContainer
|
||||
} else {
|
||||
inactiveContainer = splitShadeContainer
|
||||
activeContainer = singlePaneContainer
|
||||
}
|
||||
if (inactiveContainer?.childCount == 1) {
|
||||
inactiveContainer.removeAllViews()
|
||||
}
|
||||
if (activeContainer?.childCount == 0) {
|
||||
// Detach the hostView from its parent view if exists
|
||||
mediaHost.hostView.parent?.let {
|
||||
(it as? ViewGroup)?.removeView(mediaHost.hostView)
|
||||
}
|
||||
activeContainer.addView(mediaHost.hostView)
|
||||
}
|
||||
}
|
||||
|
||||
fun refreshMediaPosition() {
|
||||
@@ -124,35 +176,17 @@ class KeyguardMediaController @Inject constructor(
|
||||
}
|
||||
|
||||
private fun showMediaPlayer() {
|
||||
if (useSplitShadeContainer()) {
|
||||
showMediaPlayer(
|
||||
activeContainer = splitShadeContainer,
|
||||
inactiveContainer = singlePaneContainer)
|
||||
if (useSplitShade) {
|
||||
setVisibility(splitShadeContainer, View.VISIBLE)
|
||||
setVisibility(singlePaneContainer, View.GONE)
|
||||
} else {
|
||||
showMediaPlayer(
|
||||
activeContainer = singlePaneContainer,
|
||||
inactiveContainer = splitShadeContainer)
|
||||
setVisibility(singlePaneContainer, View.VISIBLE)
|
||||
setVisibility(splitShadeContainer, View.GONE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showMediaPlayer(activeContainer: ViewGroup?, inactiveContainer: ViewGroup?) {
|
||||
if (inactiveContainer?.childCount == 1) {
|
||||
inactiveContainer.removeAllViews()
|
||||
}
|
||||
// might be called a few times for the same view, no need to add hostView again
|
||||
if (activeContainer?.childCount == 0) {
|
||||
// Detach the hostView from its parent view if exists
|
||||
mediaHost.hostView.parent ?.let {
|
||||
(it as? ViewGroup)?.removeView(mediaHost.hostView)
|
||||
}
|
||||
activeContainer.addView(mediaHost.hostView)
|
||||
}
|
||||
setVisibility(activeContainer, View.VISIBLE)
|
||||
setVisibility(inactiveContainer, View.GONE)
|
||||
}
|
||||
|
||||
private fun hideMediaPlayer() {
|
||||
if (useSplitShadeContainer()) {
|
||||
if (useSplitShade) {
|
||||
setVisibility(splitShadeContainer, View.GONE)
|
||||
} else {
|
||||
setVisibility(singlePaneContainer, View.GONE)
|
||||
|
||||
@@ -27,6 +27,11 @@ class MediaHost constructor(
|
||||
|
||||
private var inited: Boolean = false
|
||||
|
||||
/**
|
||||
* Are we listening to media data changes?
|
||||
*/
|
||||
private var listeningToMediaData = false
|
||||
|
||||
/**
|
||||
* Get the current bounds on the screen. This makes sure the state is fresh and up to date
|
||||
*/
|
||||
@@ -97,18 +102,17 @@ class MediaHost constructor(
|
||||
|
||||
this.location = location
|
||||
hostView = mediaHierarchyManager.register(this)
|
||||
// Listen by default, as the host might not be attached by our clients, until
|
||||
// they get a visibility change. We still want to stay up to date in that case!
|
||||
setListeningToMediaData(true)
|
||||
hostView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
|
||||
override fun onViewAttachedToWindow(v: View?) {
|
||||
// we should listen to the combined state change, since otherwise there might
|
||||
// be a delay until the views and the controllers are initialized, leaving us
|
||||
// with either a blank view or the controllers not yet initialized and the
|
||||
// measuring wrong
|
||||
mediaDataManager.addListener(listener)
|
||||
setListeningToMediaData(true)
|
||||
updateViewVisibility()
|
||||
}
|
||||
|
||||
override fun onViewDetachedFromWindow(v: View?) {
|
||||
mediaDataManager.removeListener(listener)
|
||||
setListeningToMediaData(false)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -135,8 +139,19 @@ class MediaHost constructor(
|
||||
updateViewVisibility()
|
||||
}
|
||||
|
||||
private fun setListeningToMediaData(listen: Boolean) {
|
||||
if (listen != listeningToMediaData) {
|
||||
listeningToMediaData = listen
|
||||
if (listen) {
|
||||
mediaDataManager.addListener(listener)
|
||||
} else {
|
||||
mediaDataManager.removeListener(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateViewVisibility() {
|
||||
visible = if (showsOnlyActiveMedia) {
|
||||
state.visible = if (showsOnlyActiveMedia) {
|
||||
mediaDataManager.hasActiveMedia()
|
||||
} else {
|
||||
mediaDataManager.hasAnyMedia()
|
||||
@@ -300,7 +315,7 @@ interface MediaHostState {
|
||||
/**
|
||||
* If the view should be VISIBLE or GONE.
|
||||
*/
|
||||
var visible: Boolean
|
||||
val visible: Boolean
|
||||
|
||||
/**
|
||||
* Does this host need any falsing protection?
|
||||
|
||||
@@ -1085,8 +1085,7 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
}
|
||||
|
||||
private void attachSplitShadeMediaPlayerContainer(FrameLayout container) {
|
||||
mKeyguardMediaController.attachSplitShadeContainer(container,
|
||||
() -> mShouldUseSplitNotificationShade);
|
||||
mKeyguardMediaController.attachSplitShadeContainer(container);
|
||||
}
|
||||
|
||||
private void initBottomArea() {
|
||||
|
||||
@@ -22,13 +22,16 @@ import android.view.View.VISIBLE
|
||||
import android.widget.FrameLayout
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.FeatureFlags
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||
import com.android.systemui.statusbar.StatusBarState
|
||||
import com.android.systemui.statusbar.SysuiStatusBarStateController
|
||||
import com.android.systemui.statusbar.notification.stack.MediaHeaderView
|
||||
import com.android.systemui.statusbar.phone.KeyguardBypassController
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||
import com.android.systemui.util.animation.UniqueObjectHostView
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import junit.framework.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
@@ -48,11 +51,16 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
|
||||
@Mock
|
||||
private lateinit var statusBarStateController: SysuiStatusBarStateController
|
||||
@Mock
|
||||
private lateinit var configurationController: ConfigurationController
|
||||
@Mock
|
||||
private lateinit var featureFlags: FeatureFlags
|
||||
@Mock
|
||||
private lateinit var notificationLockscreenUserManager: NotificationLockscreenUserManager
|
||||
@JvmField @Rule
|
||||
val mockito = MockitoJUnit.rule()
|
||||
|
||||
private val mediaHeaderView: MediaHeaderView = MediaHeaderView(context, null)
|
||||
private val hostView = UniqueObjectHostView(context)
|
||||
private lateinit var keyguardMediaController: KeyguardMediaController
|
||||
|
||||
@Before
|
||||
@@ -62,10 +70,17 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
|
||||
whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
|
||||
whenever(notificationLockscreenUserManager.shouldShowLockscreenNotifications())
|
||||
.thenReturn(true)
|
||||
whenever(mediaHost.hostView).thenReturn(UniqueObjectHostView(context))
|
||||
whenever(mediaHost.hostView).thenReturn(hostView)
|
||||
|
||||
keyguardMediaController = KeyguardMediaController(mediaHost, bypassController,
|
||||
statusBarStateController, notificationLockscreenUserManager)
|
||||
keyguardMediaController = KeyguardMediaController(
|
||||
mediaHost,
|
||||
bypassController,
|
||||
statusBarStateController,
|
||||
notificationLockscreenUserManager,
|
||||
featureFlags,
|
||||
context,
|
||||
configurationController
|
||||
)
|
||||
keyguardMediaController.attachSinglePaneContainer(mediaHeaderView)
|
||||
}
|
||||
|
||||
@@ -105,11 +120,8 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testActivatesSplitShadeContainerInSplitShadeMode() {
|
||||
val splitShadeContainer = FrameLayout(context)
|
||||
keyguardMediaController.attachSplitShadeContainer(
|
||||
splitShadeContainer,
|
||||
useContainer = { true })
|
||||
|
||||
keyguardMediaController.refreshMediaPosition()
|
||||
keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
|
||||
keyguardMediaController.useSplitShade = true
|
||||
|
||||
assertThat(splitShadeContainer.visibility).isEqualTo(VISIBLE)
|
||||
}
|
||||
@@ -117,13 +129,28 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
|
||||
@Test
|
||||
fun testActivatesSinglePaneContainerInSinglePaneMode() {
|
||||
val splitShadeContainer = FrameLayout(context)
|
||||
keyguardMediaController.attachSplitShadeContainer(
|
||||
splitShadeContainer,
|
||||
useContainer = { false })
|
||||
|
||||
keyguardMediaController.refreshMediaPosition()
|
||||
keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
|
||||
|
||||
assertThat(splitShadeContainer.visibility).isEqualTo(GONE)
|
||||
assertThat(mediaHeaderView.visibility).isEqualTo(VISIBLE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAttachedToSplitShade() {
|
||||
val splitShadeContainer = FrameLayout(context)
|
||||
keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
|
||||
keyguardMediaController.useSplitShade = true
|
||||
|
||||
assertTrue("HostView wasn't attached to the split pane container",
|
||||
splitShadeContainer.childCount == 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAttachedToSinglePane() {
|
||||
val splitShadeContainer = FrameLayout(context)
|
||||
keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
|
||||
|
||||
assertTrue("HostView wasn't attached to the single pane container",
|
||||
mediaHeaderView.childCount == 1)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user