summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/ktfmt_includes.txt57
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/models/GutsViewHolder.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt122
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt62
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt86
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt223
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt110
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt44
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataProvider.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/LocalMediaManagerFactory.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataCombineLatest.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt149
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt758
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt209
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaSessionBasedFilter.kt81
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt87
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt191
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt143
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt65
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt205
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt102
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt79
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt163
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt1047
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt66
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt379
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt1017
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt193
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHostStatesManager.kt87
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaScrollView.kt93
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt437
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt46
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MetadataAnimationHandler.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt87
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFeatureFlag.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/util/MediaUiEventLogger.kt193
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/MediaTestUtils.kt56
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/MediaViewHolderTest.kt18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarObserverTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarViewModelTest.kt268
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataTest.kt61
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataFilterTest.kt134
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt883
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt58
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaSessionBasedFilterTest.kt101
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListenerTest.kt179
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt180
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserTest.kt63
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/AnimationBindHandlerTest.kt11
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/ColorSchemeTransitionTest.kt21
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt48
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt477
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt654
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt106
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaPlayerDataTest.kt160
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MetadataAnimationHandlerTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/SquigglyProgressTest.kt14
59 files changed, 5498 insertions, 4702 deletions
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 31ab24748c93..0f037e40b997 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -189,45 +189,8 @@
-packages/SystemUI/src/com/android/systemui/log/LogcatEchoTracker.kt
-packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerDebug.kt
-packages/SystemUI/src/com/android/systemui/log/LogcatEchoTrackerProd.kt
--packages/SystemUI/src/com/android/systemui/media/AnimationBindHandler.kt
--packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt
--packages/SystemUI/src/com/android/systemui/media/GutsViewHolder.kt
--packages/SystemUI/src/com/android/systemui/media/IlluminationDrawable.kt
--packages/SystemUI/src/com/android/systemui/media/KeyguardMediaController.kt
--packages/SystemUI/src/com/android/systemui/media/LightSourceDrawable.kt
--packages/SystemUI/src/com/android/systemui/media/LocalMediaManagerFactory.kt
--packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
--packages/SystemUI/src/com/android/systemui/media/MediaCarouselControllerLogger.kt
--packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt
--packages/SystemUI/src/com/android/systemui/media/MediaData.kt
--packages/SystemUI/src/com/android/systemui/media/MediaDataCombineLatest.kt
--packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
--packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt
--packages/SystemUI/src/com/android/systemui/media/MediaFeatureFlag.kt
--packages/SystemUI/src/com/android/systemui/media/MediaFlags.kt
--packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
--packages/SystemUI/src/com/android/systemui/media/MediaHost.kt
--packages/SystemUI/src/com/android/systemui/media/MediaHostStatesManager.kt
-packages/SystemUI/src/com/android/systemui/media/MediaProjectionAppSelectorActivity.kt
-packages/SystemUI/src/com/android/systemui/media/MediaProjectionCaptureTarget.kt
--packages/SystemUI/src/com/android/systemui/media/MediaResumeListener.kt
--packages/SystemUI/src/com/android/systemui/media/MediaScrollView.kt
--packages/SystemUI/src/com/android/systemui/media/MediaSessionBasedFilter.kt
--packages/SystemUI/src/com/android/systemui/media/MediaTimeoutListener.kt
--packages/SystemUI/src/com/android/systemui/media/MediaTimeoutLogger.kt
--packages/SystemUI/src/com/android/systemui/media/MediaUiEventLogger.kt
--packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
--packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
--packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt
--packages/SystemUI/src/com/android/systemui/media/MetadataAnimationHandler.kt
--packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt
--packages/SystemUI/src/com/android/systemui/media/ResumeMediaBrowserLogger.kt
--packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
--packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
--packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt
--packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaDataProvider.kt
--packages/SystemUI/src/com/android/systemui/media/SquigglyProgress.kt
-packages/SystemUI/src/com/android/systemui/media/dagger/MediaProjectionModule.kt
-packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBroadcastDialogFactory.kt
-packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialogFactory.kt
@@ -653,26 +616,6 @@
-packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardUnlockAnimationControllerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/lifecycle/InstantTaskExecutorRule.kt
-packages/SystemUI/tests/src/com/android/systemui/log/LogBufferTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/AnimationBindHandlerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/KeyguardMediaControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MediaCarouselControllerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MediaPlayerDataTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MediaResumeListenerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MediaSessionBasedFilterTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MediaTestUtils.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MediaTimeoutListenerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/MetadataAnimationHandlerTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/ResumeMediaBrowserTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/SmartspaceMediaDataTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/SquigglyProgressTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
-packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/GutsViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/GutsViewHolder.kt
index dc0ff7758f4f..531506771459 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/GutsViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/GutsViewHolder.kt
@@ -98,11 +98,6 @@ class GutsViewHolder constructor(itemView: View) {
}
companion object {
- val ids = setOf(
- R.id.remove_text,
- R.id.cancel,
- R.id.dismiss,
- R.id.settings
- )
+ val ids = setOf(R.id.remove_text, R.id.cancel, R.id.dismiss, R.id.settings)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt
index abe26f12fad2..ed649b1c0265 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaData.kt
@@ -27,69 +27,42 @@ import com.android.systemui.R
data class MediaData(
val userId: Int,
val initialized: Boolean = false,
- /**
- * App name that will be displayed on the player.
- */
+ /** App name that will be displayed on the player. */
val app: String?,
- /**
- * App icon shown on player.
- */
+ /** App icon shown on player. */
val appIcon: Icon?,
- /**
- * Artist name.
- */
+ /** Artist name. */
val artist: CharSequence?,
- /**
- * Song name.
- */
+ /** Song name. */
val song: CharSequence?,
- /**
- * Album artwork.
- */
+ /** Album artwork. */
val artwork: Icon?,
- /**
- * List of generic action buttons for the media player, based on notification actions
- */
+ /** List of generic action buttons for the media player, based on notification actions */
val actions: List<MediaAction>,
- /**
- * Same as above, but shown on smaller versions of the player, like in QQS or keyguard.
- */
+ /** Same as above, but shown on smaller versions of the player, like in QQS or keyguard. */
val actionsToShowInCompact: List<Int>,
/**
- * Semantic actions buttons, based on the PlaybackState of the media session.
- * If present, these actions will be preferred in the UI over [actions]
+ * Semantic actions buttons, based on the PlaybackState of the media session. If present, these
+ * actions will be preferred in the UI over [actions]
*/
val semanticActions: MediaButton? = null,
- /**
- * Package name of the app that's posting the media.
- */
+ /** Package name of the app that's posting the media. */
val packageName: String,
- /**
- * Unique media session identifier.
- */
+ /** Unique media session identifier. */
val token: MediaSession.Token?,
- /**
- * Action to perform when the player is tapped.
- * This is unrelated to {@link #actions}.
- */
+ /** Action to perform when the player is tapped. This is unrelated to {@link #actions}. */
val clickIntent: PendingIntent?,
- /**
- * Where the media is playing: phone, headphones, ear buds, remote session.
- */
+ /** Where the media is playing: phone, headphones, ear buds, remote session. */
val device: MediaDeviceData?,
/**
- * When active, a player will be displayed on keyguard and quick-quick settings.
- * This is unrelated to the stream being playing or not, a player will not be active if
- * timed out, or in resumption mode.
+ * When active, a player will be displayed on keyguard and quick-quick settings. This is
+ * unrelated to the stream being playing or not, a player will not be active if timed out, or in
+ * resumption mode.
*/
var active: Boolean,
- /**
- * Action that should be performed to restart a non active session.
- */
+ /** Action that should be performed to restart a non active session. */
var resumeAction: Runnable?,
- /**
- * Playback location: one of PLAYBACK_LOCAL, PLAYBACK_CAST_LOCAL, or PLAYBACK_CAST_REMOTE
- */
+ /** Playback location: one of PLAYBACK_LOCAL, PLAYBACK_CAST_LOCAL, or PLAYBACK_CAST_REMOTE */
var playbackLocation: Int = PLAYBACK_LOCAL,
/**
* Indicates that this player is a resumption player (ie. It only shows a play actions which
@@ -102,29 +75,19 @@ data class MediaData(
val notificationKey: String? = null,
var hasCheckedForResume: Boolean = false,
- /**
- * If apps do not report PlaybackState, set as null to imply 'undetermined'
- */
+ /** If apps do not report PlaybackState, set as null to imply 'undetermined' */
val isPlaying: Boolean? = null,
- /**
- * Set from the notification and used as fallback when PlaybackState cannot be determined
- */
+ /** Set from the notification and used as fallback when PlaybackState cannot be determined */
val isClearable: Boolean = true,
- /**
- * Timestamp when this player was last active.
- */
+ /** Timestamp when this player was last active. */
var lastActive: Long = 0L,
- /**
- * Instance ID for logging purposes
- */
+ /** Instance ID for logging purposes */
val instanceId: InstanceId,
- /**
- * The UID of the app, used for logging
- */
+ /** The UID of the app, used for logging */
val appUid: Int
) {
companion object {
@@ -141,37 +104,21 @@ data class MediaData(
}
}
-/**
- * Contains [MediaAction] objects which represent specific buttons in the UI
- */
+/** Contains [MediaAction] objects which represent specific buttons in the UI */
data class MediaButton(
- /**
- * Play/pause button
- */
+ /** Play/pause button */
val playOrPause: MediaAction? = null,
- /**
- * Next button, or custom action
- */
+ /** Next button, or custom action */
val nextOrCustom: MediaAction? = null,
- /**
- * Previous button, or custom action
- */
+ /** Previous button, or custom action */
val prevOrCustom: MediaAction? = null,
- /**
- * First custom action space
- */
+ /** First custom action space */
val custom0: MediaAction? = null,
- /**
- * Second custom action space
- */
+ /** Second custom action space */
val custom1: MediaAction? = null,
- /**
- * Whether to reserve the empty space when the nextOrCustom is null
- */
+ /** Whether to reserve the empty space when the nextOrCustom is null */
val reserveNext: Boolean = false,
- /**
- * Whether to reserve the empty space when the prevOrCustom is null
- */
+ /** Whether to reserve the empty space when the prevOrCustom is null */
val reservePrev: Boolean = false
) {
fun getActionById(id: Int): MediaAction? {
@@ -201,7 +148,8 @@ data class MediaAction(
/** State of the media device. */
data class MediaDeviceData
-@JvmOverloads constructor(
+@JvmOverloads
+constructor(
/** Whether or not to enable the chip */
val enabled: Boolean,
@@ -221,8 +169,8 @@ data class MediaDeviceData
val showBroadcastButton: Boolean
) {
/**
- * Check whether [MediaDeviceData] objects are equal in all fields except the icon. The icon
- * is ignored because it can change by reference frequently depending on the device type's
+ * Check whether [MediaDeviceData] objects are equal in all fields except the icon. The icon is
+ * ignored because it can change by reference frequently depending on the device type's
* implementation, but this is not usually relevant unless other info has changed
*/
fun equalsWithoutIcon(other: MediaDeviceData?): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
index d6e40ae8eacf..2511324a943e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/MediaViewHolder.kt
@@ -30,9 +30,7 @@ import com.android.systemui.util.animation.TransitionLayout
private const val TAG = "MediaViewHolder"
-/**
- * Holder class for media player view
- */
+/** Holder class for media player view */
class MediaViewHolder constructor(itemView: View) {
val player = itemView as TransitionLayout
@@ -53,8 +51,7 @@ class MediaViewHolder constructor(itemView: View) {
// These views are only shown while the user is actively scrubbing
val scrubbingElapsedTimeView: TextView =
itemView.requireViewById(R.id.media_scrubbing_elapsed_time)
- val scrubbingTotalTimeView: TextView =
- itemView.requireViewById(R.id.media_scrubbing_total_time)
+ val scrubbingTotalTimeView: TextView = itemView.requireViewById(R.id.media_scrubbing_total_time)
val gutsViewHolder = GutsViewHolder(itemView)
@@ -87,15 +84,7 @@ class MediaViewHolder constructor(itemView: View) {
}
fun getTransparentActionButtons(): List<ImageButton> {
- return listOf(
- actionNext,
- actionPrev,
- action0,
- action1,
- action2,
- action3,
- action4
- )
+ return listOf(actionNext, actionPrev, action0, action1, action2, action3, action4)
}
fun marquee(start: Boolean, delay: Long) {
@@ -109,10 +98,8 @@ class MediaViewHolder constructor(itemView: View) {
* @param inflater LayoutInflater to use to inflate the layout.
* @param parent Parent of inflated view.
*/
- @JvmStatic fun create(
- inflater: LayoutInflater,
- parent: ViewGroup
- ): MediaViewHolder {
+ @JvmStatic
+ fun create(inflater: LayoutInflater, parent: ViewGroup): MediaViewHolder {
val mediaView = inflater.inflate(R.layout.media_session_view, parent, false)
mediaView.setLayerType(View.LAYER_TYPE_HARDWARE, null)
// Because this media view (a TransitionLayout) is used to measure and layout the views
@@ -125,7 +112,8 @@ class MediaViewHolder constructor(itemView: View) {
}
}
- val controlsIds = setOf(
+ val controlsIds =
+ setOf(
R.id.icon,
R.id.app_name,
R.id.header_title,
@@ -143,27 +131,23 @@ class MediaViewHolder constructor(itemView: View) {
R.id.icon,
R.id.media_scrubbing_elapsed_time,
R.id.media_scrubbing_total_time
- )
+ )
// Buttons used for notification-based actions
- val genericButtonIds = setOf(
- R.id.action0,
- R.id.action1,
- R.id.action2,
- R.id.action3,
- R.id.action4
- )
-
- val expandedBottomActionIds = setOf(
- R.id.actionPrev,
- R.id.actionNext,
- R.id.action0,
- R.id.action1,
- R.id.action2,
- R.id.action3,
- R.id.action4,
- R.id.media_scrubbing_elapsed_time,
- R.id.media_scrubbing_total_time
- )
+ val genericButtonIds =
+ setOf(R.id.action0, R.id.action1, R.id.action2, R.id.action3, R.id.action4)
+
+ val expandedBottomActionIds =
+ setOf(
+ R.id.actionPrev,
+ R.id.actionNext,
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4,
+ R.id.media_scrubbing_elapsed_time,
+ R.id.media_scrubbing_total_time
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
index e5d774a111e0..37d956bd09eb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarObserver.kt
@@ -31,34 +31,49 @@ import com.android.systemui.media.controls.ui.SquigglyProgress
*
* <p>Updates the seek bar views in response to changes to the model.
*/
-open class SeekBarObserver(
- private val holder: MediaViewHolder
-) : Observer<SeekBarViewModel.Progress> {
+open class SeekBarObserver(private val holder: MediaViewHolder) :
+ Observer<SeekBarViewModel.Progress> {
companion object {
@JvmStatic val RESET_ANIMATION_DURATION_MS: Int = 750
@JvmStatic val RESET_ANIMATION_THRESHOLD_MS: Int = 250
}
- val seekBarEnabledMaxHeight = holder.seekBar.context.resources
- .getDimensionPixelSize(R.dimen.qs_media_enabled_seekbar_height)
- val seekBarDisabledHeight = holder.seekBar.context.resources
- .getDimensionPixelSize(R.dimen.qs_media_disabled_seekbar_height)
- val seekBarEnabledVerticalPadding = holder.seekBar.context.resources
- .getDimensionPixelSize(R.dimen.qs_media_session_enabled_seekbar_vertical_padding)
- val seekBarDisabledVerticalPadding = holder.seekBar.context.resources
- .getDimensionPixelSize(R.dimen.qs_media_session_disabled_seekbar_vertical_padding)
+ val seekBarEnabledMaxHeight =
+ holder.seekBar.context.resources.getDimensionPixelSize(
+ R.dimen.qs_media_enabled_seekbar_height
+ )
+ val seekBarDisabledHeight =
+ holder.seekBar.context.resources.getDimensionPixelSize(
+ R.dimen.qs_media_disabled_seekbar_height
+ )
+ val seekBarEnabledVerticalPadding =
+ holder.seekBar.context.resources.getDimensionPixelSize(
+ R.dimen.qs_media_session_enabled_seekbar_vertical_padding
+ )
+ val seekBarDisabledVerticalPadding =
+ holder.seekBar.context.resources.getDimensionPixelSize(
+ R.dimen.qs_media_session_disabled_seekbar_vertical_padding
+ )
var seekBarResetAnimator: Animator? = null
init {
- val seekBarProgressWavelength = holder.seekBar.context.resources
- .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_wavelength).toFloat()
- val seekBarProgressAmplitude = holder.seekBar.context.resources
- .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_amplitude).toFloat()
- val seekBarProgressPhase = holder.seekBar.context.resources
- .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_phase).toFloat()
- val seekBarProgressStrokeWidth = holder.seekBar.context.resources
- .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_stroke_width).toFloat()
+ val seekBarProgressWavelength =
+ holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_wavelength)
+ .toFloat()
+ val seekBarProgressAmplitude =
+ holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_amplitude)
+ .toFloat()
+ val seekBarProgressPhase =
+ holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_phase)
+ .toFloat()
+ val seekBarProgressStrokeWidth =
+ holder.seekBar.context.resources
+ .getDimensionPixelSize(R.dimen.qs_media_seekbar_progress_stroke_width)
+ .toFloat()
val progressDrawable = holder.seekBar.progressDrawable as? SquigglyProgress
progressDrawable?.let {
it.waveLength = seekBarProgressWavelength
@@ -98,16 +113,18 @@ open class SeekBarObserver(
}
holder.seekBar.setMax(data.duration)
- val totalTimeString = DateUtils.formatElapsedTime(
- data.duration / DateUtils.SECOND_IN_MILLIS)
+ val totalTimeString =
+ DateUtils.formatElapsedTime(data.duration / DateUtils.SECOND_IN_MILLIS)
if (data.scrubbing) {
holder.scrubbingTotalTimeView.text = totalTimeString
}
data.elapsedTime?.let {
if (!data.scrubbing && !(seekBarResetAnimator?.isRunning ?: false)) {
- if (it <= RESET_ANIMATION_THRESHOLD_MS &&
- holder.seekBar.progress > RESET_ANIMATION_THRESHOLD_MS) {
+ if (
+ it <= RESET_ANIMATION_THRESHOLD_MS &&
+ holder.seekBar.progress > RESET_ANIMATION_THRESHOLD_MS
+ ) {
// This animation resets for every additional update to zero.
val animator = buildResetAnimator(it)
animator.start()
@@ -117,24 +134,29 @@ open class SeekBarObserver(
}
}
- val elapsedTimeString = DateUtils.formatElapsedTime(
- it / DateUtils.SECOND_IN_MILLIS)
+ val elapsedTimeString = DateUtils.formatElapsedTime(it / DateUtils.SECOND_IN_MILLIS)
if (data.scrubbing) {
holder.scrubbingElapsedTimeView.text = elapsedTimeString
}
- holder.seekBar.contentDescription = holder.seekBar.context.getString(
- R.string.controls_media_seekbar_description,
- elapsedTimeString,
- totalTimeString
- )
+ holder.seekBar.contentDescription =
+ holder.seekBar.context.getString(
+ R.string.controls_media_seekbar_description,
+ elapsedTimeString,
+ totalTimeString
+ )
}
}
@VisibleForTesting
open fun buildResetAnimator(targetTime: Int): Animator {
- val animator = ObjectAnimator.ofInt(holder.seekBar, "progress",
- holder.seekBar.progress, targetTime + RESET_ANIMATION_DURATION_MS)
+ val animator =
+ ObjectAnimator.ofInt(
+ holder.seekBar,
+ "progress",
+ holder.seekBar.progress,
+ targetTime + RESET_ANIMATION_DURATION_MS
+ )
animator.setAutoCancel(true)
animator.duration = RESET_ANIMATION_DURATION_MS.toLong()
animator.interpolator = Interpolators.EMPHASIZED
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt
index e4e5cd3526a5..bba5f350dd16 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/player/SeekBarViewModel.kt
@@ -42,8 +42,8 @@ private const val MIN_FLING_VELOCITY_SCALE_FACTOR = 10
private fun PlaybackState.isInMotion(): Boolean {
return this.state == PlaybackState.STATE_PLAYING ||
- this.state == PlaybackState.STATE_FAST_FORWARDING ||
- this.state == PlaybackState.STATE_REWINDING
+ this.state == PlaybackState.STATE_FAST_FORWARDING ||
+ this.state == PlaybackState.STATE_REWINDING
}
/**
@@ -59,8 +59,8 @@ private fun PlaybackState.computePosition(duration: Long): Long {
val updateTime = this.getLastPositionUpdateTime()
val currentTime = SystemClock.elapsedRealtime()
if (updateTime > 0) {
- var position = (this.playbackSpeed * (currentTime - updateTime)).toLong() +
- this.getPosition()
+ var position =
+ (this.playbackSpeed * (currentTime - updateTime)).toLong() + this.getPosition()
if (duration >= 0 && position > duration) {
position = duration.toLong()
} else if (position < 0) {
@@ -73,7 +73,9 @@ private fun PlaybackState.computePosition(duration: Long): Long {
}
/** ViewModel for seek bar in QS media player. */
-class SeekBarViewModel @Inject constructor(
+class SeekBarViewModel
+@Inject
+constructor(
@Background private val bgExecutor: RepeatableExecutor,
private val falsingManager: FalsingManager,
) {
@@ -86,9 +88,7 @@ class SeekBarViewModel @Inject constructor(
}
_progress.postValue(value)
}
- private val _progress = MutableLiveData<Progress>().apply {
- postValue(_data)
- }
+ private val _progress = MutableLiveData<Progress>().apply { postValue(_data) }
val progress: LiveData<Progress>
get() = _progress
private var controller: MediaController? = null
@@ -100,20 +100,21 @@ class SeekBarViewModel @Inject constructor(
}
}
private var playbackState: PlaybackState? = null
- private var callback = object : MediaController.Callback() {
- override fun onPlaybackStateChanged(state: PlaybackState?) {
- playbackState = state
- if (playbackState == null || PlaybackState.STATE_NONE.equals(playbackState)) {
- clearController()
- } else {
- checkIfPollingNeeded()
+ private var callback =
+ object : MediaController.Callback() {
+ override fun onPlaybackStateChanged(state: PlaybackState?) {
+ playbackState = state
+ if (playbackState == null || PlaybackState.STATE_NONE.equals(playbackState)) {
+ clearController()
+ } else {
+ checkIfPollingNeeded()
+ }
}
- }
- override fun onSessionDestroyed() {
- clearController()
+ override fun onSessionDestroyed() {
+ clearController()
+ }
}
- }
private var cancel: Runnable? = null
/** Indicates if the seek interaction is considered a false guesture. */
@@ -121,12 +122,13 @@ class SeekBarViewModel @Inject constructor(
/** Listening state (QS open or closed) is used to control polling of progress. */
var listening = true
- set(value) = bgExecutor.execute {
- if (field != value) {
- field = value
- checkIfPollingNeeded()
+ set(value) =
+ bgExecutor.execute {
+ if (field != value) {
+ field = value
+ checkIfPollingNeeded()
+ }
}
- }
private var scrubbingChangeListener: ScrubbingChangeListener? = null
private var enabledChangeListener: EnabledChangeListener? = null
@@ -144,14 +146,13 @@ class SeekBarViewModel @Inject constructor(
lateinit var logSeek: () -> Unit
- /**
- * Event indicating that the user has started interacting with the seek bar.
- */
+ /** Event indicating that the user has started interacting with the seek bar. */
@AnyThread
- fun onSeekStarting() = bgExecutor.execute {
- scrubbing = true
- isFalseSeek = false
- }
+ fun onSeekStarting() =
+ bgExecutor.execute {
+ scrubbing = true
+ isFalseSeek = false
+ }
/**
* Event indicating that the user has moved the seek bar.
@@ -159,47 +160,51 @@ class SeekBarViewModel @Inject constructor(
* @param position Current location in the track.
*/
@AnyThread
- fun onSeekProgress(position: Long) = bgExecutor.execute {
- if (scrubbing) {
- // The user hasn't yet finished their touch gesture, so only update the data for visual
- // feedback and don't update [controller] yet.
- _data = _data.copy(elapsedTime = position.toInt())
- } else {
- // The seek progress came from an a11y action and we should immediately update to the
- // new position. (a11y actions to change the seekbar position don't trigger
- // SeekBar.OnSeekBarChangeListener.onStartTrackingTouch or onStopTrackingTouch.)
- onSeek(position)
+ fun onSeekProgress(position: Long) =
+ bgExecutor.execute {
+ if (scrubbing) {
+ // The user hasn't yet finished their touch gesture, so only update the data for
+ // visual
+ // feedback and don't update [controller] yet.
+ _data = _data.copy(elapsedTime = position.toInt())
+ } else {
+ // The seek progress came from an a11y action and we should immediately update to
+ // the
+ // new position. (a11y actions to change the seekbar position don't trigger
+ // SeekBar.OnSeekBarChangeListener.onStartTrackingTouch or onStopTrackingTouch.)
+ onSeek(position)
+ }
}
- }
- /**
- * Event indicating that the seek interaction is a false gesture and it should be ignored.
- */
+ /** Event indicating that the seek interaction is a false gesture and it should be ignored. */
@AnyThread
- fun onSeekFalse() = bgExecutor.execute {
- if (scrubbing) {
- isFalseSeek = true
+ fun onSeekFalse() =
+ bgExecutor.execute {
+ if (scrubbing) {
+ isFalseSeek = true
+ }
}
- }
/**
* Handle request to change the current position in the media track.
* @param position Place to seek to in the track.
*/
@AnyThread
- fun onSeek(position: Long) = bgExecutor.execute {
- if (isFalseSeek) {
- scrubbing = false
- checkPlaybackPosition()
- } else {
- logSeek()
- controller?.transportControls?.seekTo(position)
- // Invalidate the cached playbackState to avoid the thumb jumping back to the previous
- // position.
- playbackState = null
- scrubbing = false
+ fun onSeek(position: Long) =
+ bgExecutor.execute {
+ if (isFalseSeek) {
+ scrubbing = false
+ checkPlaybackPosition()
+ } else {
+ logSeek()
+ controller?.transportControls?.seekTo(position)
+ // Invalidate the cached playbackState to avoid the thumb jumping back to the
+ // previous
+ // position.
+ playbackState = null
+ scrubbing = false
+ }
}
- }
/**
* Updates media information.
@@ -216,11 +221,18 @@ class SeekBarViewModel @Inject constructor(
val seekAvailable = ((playbackState?.actions ?: 0L) and PlaybackState.ACTION_SEEK_TO) != 0L
val position = playbackState?.position?.toInt()
val duration = mediaMetadata?.getLong(MediaMetadata.METADATA_KEY_DURATION)?.toInt() ?: 0
- val playing = NotificationMediaManager
- .isPlayingState(playbackState?.state ?: PlaybackState.STATE_NONE)
- val enabled = if (playbackState == null ||
- playbackState?.getState() == PlaybackState.STATE_NONE ||
- (duration <= 0)) false else true
+ val playing =
+ NotificationMediaManager.isPlayingState(
+ playbackState?.state ?: PlaybackState.STATE_NONE
+ )
+ val enabled =
+ if (
+ playbackState == null ||
+ playbackState?.getState() == PlaybackState.STATE_NONE ||
+ (duration <= 0)
+ )
+ false
+ else true
_data = Progress(enabled, seekAvailable, playing, scrubbing, position, duration)
checkIfPollingNeeded()
}
@@ -231,26 +243,26 @@ class SeekBarViewModel @Inject constructor(
* This should be called when the media session behind the controller has been destroyed.
*/
@AnyThread
- fun clearController() = bgExecutor.execute {
- controller = null
- playbackState = null
- cancel?.run()
- cancel = null
- _data = _data.copy(enabled = false)
- }
+ fun clearController() =
+ bgExecutor.execute {
+ controller = null
+ playbackState = null
+ cancel?.run()
+ cancel = null
+ _data = _data.copy(enabled = false)
+ }
- /**
- * Call to clean up any resources.
- */
+ /** Call to clean up any resources. */
@AnyThread
- fun onDestroy() = bgExecutor.execute {
- controller = null
- playbackState = null
- cancel?.run()
- cancel = null
- scrubbingChangeListener = null
- enabledChangeListener = null
- }
+ fun onDestroy() =
+ bgExecutor.execute {
+ controller = null
+ playbackState = null
+ cancel?.run()
+ cancel = null
+ scrubbingChangeListener = null
+ enabledChangeListener = null
+ }
@WorkerThread
private fun checkPlaybackPosition() {
@@ -266,8 +278,12 @@ class SeekBarViewModel @Inject constructor(
val needed = listening && !scrubbing && playbackState?.isInMotion() ?: false
if (needed) {
if (cancel == null) {
- cancel = bgExecutor.executeRepeatedly(this::checkPlaybackPosition, 0L,
- POSITION_UPDATE_INTERVAL_MILLIS)
+ cancel =
+ bgExecutor.executeRepeatedly(
+ this::checkPlaybackPosition,
+ 0L,
+ POSITION_UPDATE_INTERVAL_MILLIS
+ )
}
} else {
cancel?.run()
@@ -353,9 +369,10 @@ class SeekBarViewModel @Inject constructor(
// Gesture detector helps decide which touch events to intercept.
private val detector = GestureDetectorCompat(bar.context, this)
// Velocity threshold used to decide when a fling is considered a false gesture.
- private val flingVelocity: Int = ViewConfiguration.get(bar.context).run {
- getScaledMinimumFlingVelocity() * MIN_FLING_VELOCITY_SCALE_FACTOR
- }
+ private val flingVelocity: Int =
+ ViewConfiguration.get(bar.context).run {
+ getScaledMinimumFlingVelocity() * MIN_FLING_VELOCITY_SCALE_FACTOR
+ }
// Indicates if the gesture should go to the seek bar or if it should be intercepted.
private var shouldGoToSeekBar = false
@@ -385,9 +402,9 @@ class SeekBarViewModel @Inject constructor(
/**
* Handle down events that press down on the thumb.
*
- * On the down action, determine a target box around the thumb to know when a scroll
- * gesture starts by clicking on the thumb. The target box will be used by subsequent
- * onScroll events.
+ * On the down action, determine a target box around the thumb to know when a scroll gesture
+ * starts by clicking on the thumb. The target box will be used by subsequent onScroll
+ * events.
*
* Returns true when the down event hits within the target box of the thumb.
*/
@@ -398,17 +415,19 @@ class SeekBarViewModel @Inject constructor(
// TODO: account for thumb offset
val progress = bar.getProgress()
val range = bar.max - bar.min
- val widthFraction = if (range > 0) {
- (progress - bar.min).toDouble() / range
- } else {
- 0.0
- }
+ val widthFraction =
+ if (range > 0) {
+ (progress - bar.min).toDouble() / range
+ } else {
+ 0.0
+ }
val availableWidth = bar.width - padL - padR
- val thumbX = if (bar.isLayoutRtl()) {
- padL + availableWidth * (1 - widthFraction)
- } else {
- padL + availableWidth * widthFraction
- }
+ val thumbX =
+ if (bar.isLayoutRtl()) {
+ padL + availableWidth * (1 - widthFraction)
+ } else {
+ padL + availableWidth * widthFraction
+ }
// Set the min, max boundaries of the thumb box.
// I'm cheating by using the height of the seek bar as the width of the box.
val halfHeight: Int = bar.height / 2
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt
index c34c1992919f..1a10b18a5a69 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt
@@ -35,26 +35,30 @@ class RecommendationViewHolder private constructor(itemView: View) {
// Recommendation screen
val cardIcon = itemView.requireViewById<ImageView>(R.id.recommendation_card_icon)
- val mediaCoverItems = listOf<ImageView>(
- itemView.requireViewById(R.id.media_cover1),
- itemView.requireViewById(R.id.media_cover2),
- itemView.requireViewById(R.id.media_cover3)
- )
- val mediaCoverContainers = listOf<ViewGroup>(
- itemView.requireViewById(R.id.media_cover1_container),
- itemView.requireViewById(R.id.media_cover2_container),
- itemView.requireViewById(R.id.media_cover3_container)
- )
- val mediaTitles: List<TextView> = listOf(
- itemView.requireViewById(R.id.media_title1),
- itemView.requireViewById(R.id.media_title2),
- itemView.requireViewById(R.id.media_title3)
- )
- val mediaSubtitles: List<TextView> = listOf(
- itemView.requireViewById(R.id.media_subtitle1),
- itemView.requireViewById(R.id.media_subtitle2),
- itemView.requireViewById(R.id.media_subtitle3)
- )
+ val mediaCoverItems =
+ listOf<ImageView>(
+ itemView.requireViewById(R.id.media_cover1),
+ itemView.requireViewById(R.id.media_cover2),
+ itemView.requireViewById(R.id.media_cover3)
+ )
+ val mediaCoverContainers =
+ listOf<ViewGroup>(
+ itemView.requireViewById(R.id.media_cover1_container),
+ itemView.requireViewById(R.id.media_cover2_container),
+ itemView.requireViewById(R.id.media_cover3_container)
+ )
+ val mediaTitles: List<TextView> =
+ listOf(
+ itemView.requireViewById(R.id.media_title1),
+ itemView.requireViewById(R.id.media_title2),
+ itemView.requireViewById(R.id.media_title3)
+ )
+ val mediaSubtitles: List<TextView> =
+ listOf(
+ itemView.requireViewById(R.id.media_subtitle1),
+ itemView.requireViewById(R.id.media_subtitle2),
+ itemView.requireViewById(R.id.media_subtitle3)
+ )
val gutsViewHolder = GutsViewHolder(itemView)
@@ -78,13 +82,14 @@ class RecommendationViewHolder private constructor(itemView: View) {
* @param inflater LayoutInflater to use to inflate the layout.
* @param parent Parent of inflated view.
*/
- @JvmStatic fun create(inflater: LayoutInflater, parent: ViewGroup):
- RecommendationViewHolder {
+ @JvmStatic
+ fun create(inflater: LayoutInflater, parent: ViewGroup): RecommendationViewHolder {
val itemView =
inflater.inflate(
R.layout.media_smartspace_recommendations,
parent,
- false /* attachToRoot */)
+ false /* attachToRoot */
+ )
// Because this media view (a TransitionLayout) is used to measure and layout the views
// in various states before being attached to its parent, we can't depend on the default
// LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction.
@@ -93,35 +98,38 @@ class RecommendationViewHolder private constructor(itemView: View) {
}
// Res Ids for the control components on the recommendation view.
- val controlsIds = setOf(
- R.id.recommendation_card_icon,
- R.id.media_cover1,
- R.id.media_cover2,
- R.id.media_cover3,
- R.id.media_cover1_container,
- R.id.media_cover2_container,
- R.id.media_cover3_container,
- R.id.media_title1,
- R.id.media_title2,
- R.id.media_title3,
- R.id.media_subtitle1,
- R.id.media_subtitle2,
- R.id.media_subtitle3
- )
+ val controlsIds =
+ setOf(
+ R.id.recommendation_card_icon,
+ R.id.media_cover1,
+ R.id.media_cover2,
+ R.id.media_cover3,
+ R.id.media_cover1_container,
+ R.id.media_cover2_container,
+ R.id.media_cover3_container,
+ R.id.media_title1,
+ R.id.media_title2,
+ R.id.media_title3,
+ R.id.media_subtitle1,
+ R.id.media_subtitle2,
+ R.id.media_subtitle3
+ )
- val mediaTitlesAndSubtitlesIds = setOf(
- R.id.media_title1,
- R.id.media_title2,
- R.id.media_title3,
- R.id.media_subtitle1,
- R.id.media_subtitle2,
- R.id.media_subtitle3
- )
+ val mediaTitlesAndSubtitlesIds =
+ setOf(
+ R.id.media_title1,
+ R.id.media_title2,
+ R.id.media_title3,
+ R.id.media_subtitle1,
+ R.id.media_subtitle2,
+ R.id.media_subtitle3
+ )
- val mediaContainersIds = setOf(
- R.id.media_cover1_container,
- R.id.media_cover2_container,
- R.id.media_cover3_container
- )
+ val mediaContainersIds =
+ setOf(
+ R.id.media_cover1_container,
+ R.id.media_cover2_container,
+ R.id.media_cover3_container
+ )
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt
index eed725876349..1df42c641df6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaData.kt
@@ -25,55 +25,38 @@ import android.util.Log
import androidx.annotation.VisibleForTesting
import com.android.internal.logging.InstanceId
-@VisibleForTesting
-const val KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME"
+@VisibleForTesting const val KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME"
/** State of a Smartspace media recommendations view. */
data class SmartspaceMediaData(
- /**
- * Unique id of a Smartspace media target.
- */
+ /** Unique id of a Smartspace media target. */
val targetId: String,
- /**
- * Indicates if the status is active.
- */
+ /** Indicates if the status is active. */
val isActive: Boolean,
- /**
- * Package name of the media recommendations' provider-app.
- */
+ /** Package name of the media recommendations' provider-app. */
val packageName: String,
- /**
- * Action to perform when the card is tapped. Also contains the target's extra info.
- */
+ /** Action to perform when the card is tapped. Also contains the target's extra info. */
val cardAction: SmartspaceAction?,
- /**
- * List of media recommendations.
- */
+ /** List of media recommendations. */
val recommendations: List<SmartspaceAction>,
- /**
- * Intent for the user's initiated dismissal.
- */
+ /** Intent for the user's initiated dismissal. */
val dismissIntent: Intent?,
- /**
- * The timestamp in milliseconds that headphone is connected.
- */
+ /** The timestamp in milliseconds that headphone is connected. */
val headphoneConnectionTimeMillis: Long,
- /**
- * Instance ID for [MediaUiEventLogger]
- */
+ /** Instance ID for [MediaUiEventLogger] */
val instanceId: InstanceId
) {
/**
* Indicates if all the data is valid.
*
* TODO(b/230333302): Make MediaControlPanel more flexible so that we can display fewer than
+ * ```
* [NUM_REQUIRED_RECOMMENDATIONS].
+ * ```
*/
fun isValid() = getValidRecommendations().size >= NUM_REQUIRED_RECOMMENDATIONS
- /**
- * Returns the list of [recommendations] that have valid data.
- */
+ /** Returns the list of [recommendations] that have valid data. */
fun getValidRecommendations() = recommendations.filter { it.icon != null }
/** Returns the upstream app name if available. */
@@ -92,7 +75,8 @@ data class SmartspaceMediaData(
Log.w(
TAG,
"Package $packageName does not have a main launcher activity. " +
- "Fallback to full app name")
+ "Fallback to full app name"
+ )
return try {
val applicationInfo = packageManager.getApplicationInfo(packageName, /* flags= */ 0)
packageManager.getApplicationLabel(applicationInfo)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataProvider.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataProvider.kt
index b30555b20547..a7ed69a9ab73 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataProvider.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.media.controls.models.recommendation
import android.app.smartspace.SmartspaceTarget
@@ -23,7 +39,7 @@ class SmartspaceMediaDataProvider @Inject constructor() : BcSmartspaceDataPlugin
smartspaceMediaTargetListeners.remove(smartspaceTargetListener)
}
- /** Updates Smartspace data and propagates it to any listeners. */
+ /** Updates Smartspace data and propagates it to any listeners. */
override fun onTargetsAvailable(targets: List<SmartspaceTarget>) {
// Filter out non-media targets.
val mediaTargets = mutableListOf<SmartspaceTarget>()
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/LocalMediaManagerFactory.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/LocalMediaManagerFactory.kt
index 9d3a1bd2c8c8..ff763d81f950 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/LocalMediaManagerFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/LocalMediaManagerFactory.kt
@@ -17,17 +17,15 @@
package com.android.systemui.media.controls.pipeline
import android.content.Context
-
import com.android.settingslib.bluetooth.LocalBluetoothManager
import com.android.settingslib.media.InfoMediaManager
import com.android.settingslib.media.LocalMediaManager
-
import javax.inject.Inject
-/**
- * Factory to create [LocalMediaManager] objects.
- */
-class LocalMediaManagerFactory @Inject constructor(
+/** Factory to create [LocalMediaManager] objects. */
+class LocalMediaManagerFactory
+@Inject
+constructor(
private val context: Context,
private val localBluetoothManager: LocalBluetoothManager?
) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataCombineLatest.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataCombineLatest.kt
index 1f81d8d20b67..789ef407ea9d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataCombineLatest.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataCombineLatest.kt
@@ -21,11 +21,9 @@ import com.android.systemui.media.controls.models.player.MediaDeviceData
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData
import javax.inject.Inject
-/**
- * Combines [MediaDataManager.Listener] events with [MediaDeviceManager.Listener] events.
- */
-class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
- MediaDeviceManager.Listener {
+/** Combines [MediaDataManager.Listener] events with [MediaDeviceManager.Listener] events. */
+class MediaDataCombineLatest @Inject constructor() :
+ MediaDataManager.Listener, MediaDeviceManager.Listener {
private val listeners: MutableSet<MediaDataManager.Listener> = mutableSetOf()
private val entries: MutableMap<String, Pair<MediaData?, MediaDeviceData?>> = mutableMapOf()
@@ -63,11 +61,7 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
listeners.toSet().forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
}
- override fun onMediaDeviceChanged(
- key: String,
- oldKey: String?,
- data: MediaDeviceData?
- ) {
+ override fun onMediaDeviceChanged(key: String, oldKey: String?, data: MediaDeviceData?) {
if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
entries[key] = entries.remove(oldKey)?.first to data
update(key, oldKey)
@@ -86,9 +80,7 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
*/
fun addListener(listener: MediaDataManager.Listener) = listeners.add(listener)
- /**
- * Remove a listener registered with addListener.
- */
+ /** Remove a listener registered with addListener. */
fun removeListener(listener: MediaDataManager.Listener) = listeners.remove(listener)
private fun update(key: String, oldKey: String?) {
@@ -96,18 +88,14 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
if (entry != null && device != null) {
val data = entry.copy(device = device)
val listenersCopy = listeners.toSet()
- listenersCopy.forEach {
- it.onMediaDataLoaded(key, oldKey, data)
- }
+ listenersCopy.forEach { it.onMediaDataLoaded(key, oldKey, data) }
}
}
private fun remove(key: String) {
entries.remove(key)?.let {
val listenersCopy = listeners.toSet()
- listenersCopy.forEach {
- it.onMediaDataRemoved(key)
- }
+ listenersCopy.forEach { it.onMediaDataRemoved(key) }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt
index b019086a2c6b..45b319b274b2 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataFilter.kt
@@ -23,9 +23,9 @@ import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData
+import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.settings.CurrentUserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.util.time.SystemClock
@@ -37,7 +37,8 @@ import kotlin.collections.LinkedHashMap
private const val TAG = "MediaDataFilter"
private const val DEBUG = true
-private const val EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME = ("com.google" +
+private const val EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME =
+ ("com.google" +
".android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity")
private const val RESUMABLE_MEDIA_MAX_AGE_SECONDS_KEY = "resumable_media_max_age_seconds"
@@ -46,8 +47,8 @@ private const val RESUMABLE_MEDIA_MAX_AGE_SECONDS_KEY = "resumable_media_max_age
* available within this time window, smartspace recommendations will be shown instead.
*/
@VisibleForTesting
-internal val SMARTSPACE_MAX_AGE = SystemProperties
- .getLong("debug.sysui.smartspace_max_age", TimeUnit.MINUTES.toMillis(30))
+internal val SMARTSPACE_MAX_AGE =
+ SystemProperties.getLong("debug.sysui.smartspace_max_age", TimeUnit.MINUTES.toMillis(30))
/**
* Filters data updates from [MediaDataCombineLatest] based on the current user ID, and handles user
@@ -57,7 +58,9 @@ internal val SMARTSPACE_MAX_AGE = SystemProperties
* This is added at the end of the pipeline since we may still need to handle callbacks from
* background users (e.g. timeouts).
*/
-class MediaDataFilter @Inject constructor(
+class MediaDataFilter
+@Inject
+constructor(
private val context: Context,
private val broadcastDispatcher: BroadcastDispatcher,
private val broadcastSender: BroadcastSender,
@@ -79,12 +82,13 @@ class MediaDataFilter @Inject constructor(
private var reactivatedKey: String? = null
init {
- userTracker = object : CurrentUserTracker(broadcastDispatcher) {
- override fun onUserSwitched(newUserId: Int) {
- // Post this so we can be sure lockscreenUserManager already got the broadcast
- executor.execute { handleUserSwitched(newUserId) }
+ userTracker =
+ object : CurrentUserTracker(broadcastDispatcher) {
+ override fun onUserSwitched(newUserId: Int) {
+ // Post this so we can be sure lockscreenUserManager already got the broadcast
+ executor.execute { handleUserSwitched(newUserId) }
+ }
}
- }
userTracker.startTracking()
}
@@ -111,9 +115,7 @@ class MediaDataFilter @Inject constructor(
userEntries.put(key, data)
// Notify listeners
- listeners.forEach {
- it.onMediaDataLoaded(key, oldKey, data)
- }
+ listeners.forEach { it.onMediaDataLoaded(key, oldKey, data) }
}
override fun onSmartspaceMediaDataLoaded(
@@ -131,14 +133,11 @@ class MediaDataFilter @Inject constructor(
smartspaceMediaData = data
// Before forwarding the smartspace target, first check if we have recently inactive media
- val sorted = userEntries.toSortedMap(compareBy {
- userEntries.get(it)?.lastActive ?: -1
- })
+ val sorted = userEntries.toSortedMap(compareBy { userEntries.get(it)?.lastActive ?: -1 })
val timeSinceActive = timeSinceActiveForMostRecentMedia(sorted)
var smartspaceMaxAgeMillis = SMARTSPACE_MAX_AGE
data.cardAction?.let {
- val smartspaceMaxAgeSeconds =
- it.extras.getLong(RESUMABLE_MEDIA_MAX_AGE_SECONDS_KEY, 0)
+ val smartspaceMaxAgeSeconds = it.extras.getLong(RESUMABLE_MEDIA_MAX_AGE_SECONDS_KEY, 0)
if (smartspaceMaxAgeSeconds > 0) {
smartspaceMaxAgeMillis = TimeUnit.SECONDS.toMillis(smartspaceMaxAgeSeconds)
}
@@ -155,13 +154,21 @@ class MediaDataFilter @Inject constructor(
Log.d(TAG, "reactivating $lastActiveKey instead of smartspace")
reactivatedKey = lastActiveKey
val mediaData = sorted.get(lastActiveKey)!!.copy(active = true)
- logger.logRecommendationActivated(mediaData.appUid, mediaData.packageName,
- mediaData.instanceId)
+ logger.logRecommendationActivated(
+ mediaData.appUid,
+ mediaData.packageName,
+ mediaData.instanceId
+ )
listeners.forEach {
- it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData,
- receivedSmartspaceCardLatency =
+ it.onMediaDataLoaded(
+ lastActiveKey,
+ lastActiveKey,
+ mediaData,
+ receivedSmartspaceCardLatency =
(systemClock.currentTimeMillis() - data.headphoneConnectionTimeMillis)
- .toInt(), isSsReactivated = true)
+ .toInt(),
+ isSsReactivated = true
+ )
}
}
} else {
@@ -173,8 +180,10 @@ class MediaDataFilter @Inject constructor(
Log.d(TAG, "Invalid recommendation data. Skip showing the rec card")
return
}
- logger.logRecommendationAdded(smartspaceMediaData.packageName,
- smartspaceMediaData.instanceId)
+ logger.logRecommendationAdded(
+ smartspaceMediaData.packageName,
+ smartspaceMediaData.instanceId
+ )
listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data, shouldPrioritizeMutable) }
}
@@ -182,9 +191,7 @@ class MediaDataFilter @Inject constructor(
allEntries.remove(key)
userEntries.remove(key)?.let {
// Only notify listeners if something actually changed
- listeners.forEach {
- it.onMediaDataRemoved(key)
- }
+ listeners.forEach { it.onMediaDataRemoved(key) }
}
}
@@ -197,16 +204,17 @@ class MediaDataFilter @Inject constructor(
// Notify listeners to update with actual active value
userEntries.get(lastActiveKey)?.let { mediaData ->
listeners.forEach {
- it.onMediaDataLoaded(
- lastActiveKey, lastActiveKey, mediaData, immediately)
+ it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData, immediately)
}
}
}
if (smartspaceMediaData.isActive) {
- smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
- targetId = smartspaceMediaData.targetId,
- instanceId = smartspaceMediaData.instanceId)
+ smartspaceMediaData =
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ targetId = smartspaceMediaData.targetId,
+ instanceId = smartspaceMediaData.instanceId
+ )
}
listeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
}
@@ -221,25 +229,19 @@ class MediaDataFilter @Inject constructor(
userEntries.clear()
keyCopy.forEach {
if (DEBUG) Log.d(TAG, "Removing $it after user change")
- listenersCopy.forEach { listener ->
- listener.onMediaDataRemoved(it)
- }
+ listenersCopy.forEach { listener -> listener.onMediaDataRemoved(it) }
}
allEntries.forEach { (key, data) ->
if (lockscreenUserManager.isCurrentProfile(data.userId)) {
if (DEBUG) Log.d(TAG, "Re-adding $key after user change")
userEntries.put(key, data)
- listenersCopy.forEach { listener ->
- listener.onMediaDataLoaded(key, null, data)
- }
+ listenersCopy.forEach { listener -> listener.onMediaDataLoaded(key, null, data) }
}
}
}
- /**
- * Invoked when the user has dismissed the media carousel
- */
+ /** Invoked when the user has dismissed the media carousel */
fun onSwipeToDismiss() {
if (DEBUG) Log.d(TAG, "Media carousel swiped away")
val mediaKeys = userEntries.keys.toSet()
@@ -250,55 +252,52 @@ class MediaDataFilter @Inject constructor(
if (smartspaceMediaData.isActive) {
val dismissIntent = smartspaceMediaData.dismissIntent
if (dismissIntent == null) {
- Log.w(TAG, "Cannot create dismiss action click action: " +
- "extras missing dismiss_intent.")
- } else if (dismissIntent.getComponent() != null &&
- dismissIntent.getComponent().getClassName()
- == EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME) {
+ Log.w(
+ TAG,
+ "Cannot create dismiss action click action: " + "extras missing dismiss_intent."
+ )
+ } else if (
+ dismissIntent.getComponent() != null &&
+ dismissIntent.getComponent().getClassName() ==
+ EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME
+ ) {
// Dismiss the card Smartspace data through Smartspace trampoline activity.
context.startActivity(dismissIntent)
} else {
broadcastSender.sendBroadcast(dismissIntent)
}
- smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
- targetId = smartspaceMediaData.targetId,
- instanceId = smartspaceMediaData.instanceId)
- mediaDataManager.dismissSmartspaceRecommendation(smartspaceMediaData.targetId,
- delay = 0L)
+ smartspaceMediaData =
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ targetId = smartspaceMediaData.targetId,
+ instanceId = smartspaceMediaData.instanceId
+ )
+ mediaDataManager.dismissSmartspaceRecommendation(
+ smartspaceMediaData.targetId,
+ delay = 0L
+ )
}
}
- /**
- * Are there any active media entries, including the recommendation?
- */
- fun hasActiveMediaOrRecommendation() = userEntries.any { it.value.active } ||
+ /** Are there any active media entries, including the recommendation? */
+ fun hasActiveMediaOrRecommendation() =
+ userEntries.any { it.value.active } ||
(smartspaceMediaData.isActive &&
(smartspaceMediaData.isValid() || reactivatedKey != null))
- /**
- * Are there any media entries we should display?
- */
- fun hasAnyMediaOrRecommendation() = userEntries.isNotEmpty() ||
- (smartspaceMediaData.isActive && smartspaceMediaData.isValid())
+ /** Are there any media entries we should display? */
+ fun hasAnyMediaOrRecommendation() =
+ userEntries.isNotEmpty() || (smartspaceMediaData.isActive && smartspaceMediaData.isValid())
- /**
- * Are there any media notifications active (excluding the recommendation)?
- */
+ /** Are there any media notifications active (excluding the recommendation)? */
fun hasActiveMedia() = userEntries.any { it.value.active }
- /**
- * Are there any media entries we should display (excluding the recommendation)?
- */
+ /** Are there any media entries we should display (excluding the recommendation)? */
fun hasAnyMedia() = userEntries.isNotEmpty()
- /**
- * Add a listener for filtered [MediaData] changes
- */
+ /** Add a listener for filtered [MediaData] changes */
fun addListener(listener: MediaDataManager.Listener) = _listeners.add(listener)
- /**
- * Remove a listener that was registered with addListener
- */
+ /** Remove a listener that was registered with addListener */
fun removeListener(listener: MediaDataManager.Listener) = _listeners.remove(listener)
/**
@@ -318,8 +317,6 @@ class MediaDataFilter @Inject constructor(
val now = systemClock.elapsedRealtime()
val lastActiveKey = sortedEntries.lastKey() // most recently active
- return sortedEntries.get(lastActiveKey)?.let {
- now - it.lastActive
- } ?: Long.MAX_VALUE
+ return sortedEntries.get(lastActiveKey)?.let { now - it.lastActive } ?: Long.MAX_VALUE
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
index 0d1699275d2e..14dd99023b92 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
@@ -57,10 +57,6 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
-import com.android.systemui.media.controls.util.MediaControllerFactory
-import com.android.systemui.media.controls.util.MediaFlags
-import com.android.systemui.media.controls.resume.MediaResumeListener
-import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.media.controls.models.player.MediaAction
import com.android.systemui.media.controls.models.player.MediaButton
import com.android.systemui.media.controls.models.player.MediaData
@@ -68,6 +64,10 @@ import com.android.systemui.media.controls.models.player.MediaDeviceData
import com.android.systemui.media.controls.models.player.MediaViewHolder
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaDataProvider
+import com.android.systemui.media.controls.resume.MediaResumeListener
+import com.android.systemui.media.controls.util.MediaControllerFactory
+import com.android.systemui.media.controls.util.MediaFlags
+import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.BcSmartspaceDataPlugin
import com.android.systemui.statusbar.NotificationMediaManager.isConnectingState
@@ -86,17 +86,19 @@ import java.util.concurrent.Executors
import javax.inject.Inject
// URI fields to try loading album art from
-private val ART_URIS = arrayOf(
+private val ART_URIS =
+ arrayOf(
MediaMetadata.METADATA_KEY_ALBUM_ART_URI,
MediaMetadata.METADATA_KEY_ART_URI,
MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI
-)
+ )
private const val TAG = "MediaDataManager"
private const val DEBUG = true
private const val EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY = "dismiss_intent"
-private val LOADING = MediaData(
+private val LOADING =
+ MediaData(
userId = -1,
initialized = false,
app = null,
@@ -113,37 +115,41 @@ private val LOADING = MediaData(
active = true,
resumeAction = null,
instanceId = InstanceId.fakeInstanceId(-1),
- appUid = Process.INVALID_UID)
+ appUid = Process.INVALID_UID
+ )
@VisibleForTesting
-internal val EMPTY_SMARTSPACE_MEDIA_DATA = SmartspaceMediaData(
- targetId = "INVALID",
- isActive = false,
- packageName = "INVALID",
- cardAction = null,
- recommendations = emptyList(),
- dismissIntent = null,
- headphoneConnectionTimeMillis = 0,
- instanceId = InstanceId.fakeInstanceId(-1))
+internal val EMPTY_SMARTSPACE_MEDIA_DATA =
+ SmartspaceMediaData(
+ targetId = "INVALID",
+ isActive = false,
+ packageName = "INVALID",
+ cardAction = null,
+ recommendations = emptyList(),
+ dismissIntent = null,
+ headphoneConnectionTimeMillis = 0,
+ instanceId = InstanceId.fakeInstanceId(-1)
+ )
fun isMediaNotification(sbn: StatusBarNotification): Boolean {
return sbn.notification.isMediaNotification()
}
/**
- * Allow recommendations from smartspace to show in media controls.
- * Requires [Utils.useQsMediaPlayer] to be enabled.
- * On by default, but can be disabled by setting to 0
+ * Allow recommendations from smartspace to show in media controls. Requires
+ * [Utils.useQsMediaPlayer] to be enabled. On by default, but can be disabled by setting to 0
*/
private fun allowMediaRecommendations(context: Context): Boolean {
- val flag = Settings.Secure.getInt(context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 1)
+ val flag =
+ Settings.Secure.getInt(
+ context.contentResolver,
+ Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
+ 1
+ )
return Utils.useQsMediaPlayer(context) && flag > 0
}
-/**
- * A class that facilitates management and loading of Media Data, ready for binding.
- */
+/** A class that facilitates management and loading of Media Data, ready for binding. */
@SysUISingleton
class MediaDataManager(
private val context: Context,
@@ -170,24 +176,24 @@ class MediaDataManager(
companion object {
// UI surface label for subscribing Smartspace updates.
- @JvmField
- val SMARTSPACE_UI_SURFACE_LABEL = "media_data_manager"
+ @JvmField val SMARTSPACE_UI_SURFACE_LABEL = "media_data_manager"
// Smartspace package name's extra key.
- @JvmField
- val EXTRAS_MEDIA_SOURCE_PACKAGE_NAME = "package_name"
+ @JvmField val EXTRAS_MEDIA_SOURCE_PACKAGE_NAME = "package_name"
// Maximum number of actions allowed in compact view
- @JvmField
- val MAX_COMPACT_ACTIONS = 3
+ @JvmField val MAX_COMPACT_ACTIONS = 3
// Maximum number of actions allowed in expanded view
- @JvmField
- val MAX_NOTIFICATION_ACTIONS = MediaViewHolder.genericButtonIds.size
+ @JvmField val MAX_NOTIFICATION_ACTIONS = MediaViewHolder.genericButtonIds.size
}
- private val themeText = com.android.settingslib.Utils.getColorAttr(context,
- com.android.internal.R.attr.textColorPrimary).defaultColor
+ private val themeText =
+ com.android.settingslib.Utils.getColorAttr(
+ context,
+ com.android.internal.R.attr.textColorPrimary
+ )
+ .defaultColor
// Internal listeners are part of the internal pipeline. External listeners (those registered
// with [MediaDeviceManager.addListener]) receive events after they have propagated through
@@ -203,9 +209,7 @@ class MediaDataManager(
private var smartspaceSession: SmartspaceSession? = null
private var allowMediaRecommendations = allowMediaRecommendations(context)
- /**
- * Check whether this notification is an RCN
- */
+ /** Check whether this notification is an RCN */
private fun isRemoteCastNotification(sbn: StatusBarNotification): Boolean {
return sbn.notification.extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)
}
@@ -230,29 +234,44 @@ class MediaDataManager(
tunerService: TunerService,
mediaFlags: MediaFlags,
logger: MediaUiEventLogger
- ) : this(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory,
- broadcastDispatcher, dumpManager, mediaTimeoutListener, mediaResumeListener,
- mediaSessionBasedFilter, mediaDeviceManager, mediaDataCombineLatest, mediaDataFilter,
- activityStarter, smartspaceMediaDataProvider, Utils.useMediaResumption(context),
- Utils.useQsMediaPlayer(context), clock, tunerService, mediaFlags, logger)
-
- private val appChangeReceiver = object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- when (intent.action) {
- Intent.ACTION_PACKAGES_SUSPENDED -> {
- val packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST)
- packages?.forEach {
- removeAllForPackage(it)
+ ) : this(
+ context,
+ backgroundExecutor,
+ foregroundExecutor,
+ mediaControllerFactory,
+ broadcastDispatcher,
+ dumpManager,
+ mediaTimeoutListener,
+ mediaResumeListener,
+ mediaSessionBasedFilter,
+ mediaDeviceManager,
+ mediaDataCombineLatest,
+ mediaDataFilter,
+ activityStarter,
+ smartspaceMediaDataProvider,
+ Utils.useMediaResumption(context),
+ Utils.useQsMediaPlayer(context),
+ clock,
+ tunerService,
+ mediaFlags,
+ logger
+ )
+
+ private val appChangeReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ when (intent.action) {
+ Intent.ACTION_PACKAGES_SUSPENDED -> {
+ val packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST)
+ packages?.forEach { removeAllForPackage(it) }
}
- }
- Intent.ACTION_PACKAGE_REMOVED, Intent.ACTION_PACKAGE_RESTARTED -> {
- intent.data?.encodedSchemeSpecificPart?.let {
- removeAllForPackage(it)
+ Intent.ACTION_PACKAGE_REMOVED,
+ Intent.ACTION_PACKAGE_RESTARTED -> {
+ intent.data?.encodedSchemeSpecificPart?.let { removeAllForPackage(it) }
}
}
}
}
- }
init {
dumpManager.registerDumpable(TAG, this)
@@ -273,20 +292,23 @@ class MediaDataManager(
// Set up links back into the pipeline for listeners that need to send events upstream.
mediaTimeoutListener.timeoutCallback = { key: String, timedOut: Boolean ->
- setTimedOut(key, timedOut) }
+ setTimedOut(key, timedOut)
+ }
mediaTimeoutListener.stateCallback = { key: String, state: PlaybackState ->
- updateState(key, state) }
+ updateState(key, state)
+ }
mediaResumeListener.setManager(this)
mediaDataFilter.mediaDataManager = this
val suspendFilter = IntentFilter(Intent.ACTION_PACKAGES_SUSPENDED)
broadcastDispatcher.registerReceiver(appChangeReceiver, suspendFilter, null, UserHandle.ALL)
- val uninstallFilter = IntentFilter().apply {
- addAction(Intent.ACTION_PACKAGE_REMOVED)
- addAction(Intent.ACTION_PACKAGE_RESTARTED)
- addDataScheme("package")
- }
+ val uninstallFilter =
+ IntentFilter().apply {
+ addAction(Intent.ACTION_PACKAGE_REMOVED)
+ addAction(Intent.ACTION_PACKAGE_RESTARTED)
+ addDataScheme("package")
+ }
// BroadcastDispatcher does not allow filters with data schemes
context.registerReceiver(appChangeReceiver, uninstallFilter)
@@ -294,8 +316,10 @@ class MediaDataManager(
smartspaceMediaDataProvider.registerListener(this)
val smartspaceManager: SmartspaceManager =
context.getSystemService(SmartspaceManager::class.java)
- smartspaceSession = smartspaceManager.createSmartspaceSession(
- SmartspaceConfig.Builder(context, SMARTSPACE_UI_SURFACE_LABEL).build())
+ smartspaceSession =
+ smartspaceManager.createSmartspaceSession(
+ SmartspaceConfig.Builder(context, SMARTSPACE_UI_SURFACE_LABEL).build()
+ )
smartspaceSession?.let {
it.addOnTargetsAvailableListener(
// Use a new thread listening to Smartspace updates instead of using the existing
@@ -307,17 +331,24 @@ class MediaDataManager(
Executors.newCachedThreadPool(),
SmartspaceSession.OnTargetsAvailableListener { targets ->
smartspaceMediaDataProvider.onTargetsAvailable(targets)
- })
+ }
+ )
}
smartspaceSession?.let { it.requestSmartspaceUpdate() }
- tunerService.addTunable(object : TunerService.Tunable {
- override fun onTuningChanged(key: String?, newValue: String?) {
- allowMediaRecommendations = allowMediaRecommendations(context)
- if (!allowMediaRecommendations) {
- dismissSmartspaceRecommendation(key = smartspaceMediaData.targetId, delay = 0L)
+ tunerService.addTunable(
+ object : TunerService.Tunable {
+ override fun onTuningChanged(key: String?, newValue: String?) {
+ allowMediaRecommendations = allowMediaRecommendations(context)
+ if (!allowMediaRecommendations) {
+ dismissSmartspaceRecommendation(
+ key = smartspaceMediaData.targetId,
+ delay = 0L
+ )
+ }
}
- }
- }, Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION)
+ },
+ Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION
+ )
}
fun destroy() {
@@ -332,10 +363,7 @@ class MediaDataManager(
val oldKey = findExistingEntry(key, sbn.packageName)
if (oldKey == null) {
val instanceId = logger.getNewInstanceId()
- val temp = LOADING.copy(
- packageName = sbn.packageName,
- instanceId = instanceId
- )
+ val temp = LOADING.copy(packageName = sbn.packageName, instanceId = instanceId)
mediaEntries.put(key, temp)
logEvent = true
} else if (oldKey != key) {
@@ -353,9 +381,7 @@ class MediaDataManager(
private fun removeAllForPackage(packageName: String) {
Assert.isMainThread()
val toRemove = mediaEntries.filter { it.value.packageName == packageName }
- toRemove.forEach {
- removeEntry(it.key)
- }
+ toRemove.forEach { removeEntry(it.key) }
}
fun setResumeAction(key: String, action: Runnable?) {
@@ -377,32 +403,41 @@ class MediaDataManager(
// Resume controls don't have a notification key, so store by package name instead
if (!mediaEntries.containsKey(packageName)) {
val instanceId = logger.getNewInstanceId()
- val appUid = try {
- context.packageManager.getApplicationInfo(packageName, 0)?.uid!!
- } catch (e: PackageManager.NameNotFoundException) {
- Log.w(TAG, "Could not get app UID for $packageName", e)
- Process.INVALID_UID
- }
+ val appUid =
+ try {
+ context.packageManager.getApplicationInfo(packageName, 0)?.uid!!
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.w(TAG, "Could not get app UID for $packageName", e)
+ Process.INVALID_UID
+ }
- val resumeData = LOADING.copy(
- packageName = packageName,
- resumeAction = action,
- hasCheckedForResume = true,
- instanceId = instanceId,
- appUid = appUid
- )
+ val resumeData =
+ LOADING.copy(
+ packageName = packageName,
+ resumeAction = action,
+ hasCheckedForResume = true,
+ instanceId = instanceId,
+ appUid = appUid
+ )
mediaEntries.put(packageName, resumeData)
logger.logResumeMediaAdded(appUid, packageName, instanceId)
}
backgroundExecutor.execute {
- loadMediaDataInBgForResumption(userId, desc, action, token, appName, appIntent,
- packageName)
+ loadMediaDataInBgForResumption(
+ userId,
+ desc,
+ action,
+ token,
+ appName,
+ appIntent,
+ packageName
+ )
}
}
/**
- * Check if there is an existing entry that matches the key or package name.
- * Returns the key that matches, or null if not found.
+ * Check if there is an existing entry that matches the key or package name. Returns the key
+ * that matches, or null if not found.
*/
private fun findExistingEntry(key: String, packageName: String): String? {
if (mediaEntries.containsKey(key)) {
@@ -421,32 +456,24 @@ class MediaDataManager(
oldKey: String?,
logEvent: Boolean = false
) {
- backgroundExecutor.execute {
- loadMediaDataInBg(key, sbn, oldKey, logEvent)
- }
+ backgroundExecutor.execute { loadMediaDataInBg(key, sbn, oldKey, logEvent) }
}
- /**
- * Add a listener for changes in this class
- */
+ /** Add a listener for changes in this class */
fun addListener(listener: Listener) {
// mediaDataFilter is the current end of the internal pipeline. Register external
// listeners as listeners to it.
mediaDataFilter.addListener(listener)
}
- /**
- * Remove a listener for changes in this class
- */
+ /** Remove a listener for changes in this class */
fun removeListener(listener: Listener) {
// Since mediaDataFilter is the current end of the internal pipelie, external listeners
// have been registered to it. So, they need to be removed from it too.
mediaDataFilter.removeListener(listener)
}
- /**
- * Add a listener for internal events.
- */
+ /** Add a listener for internal events. */
private fun addInternalListener(listener: Listener) = internalListeners.add(listener)
/**
@@ -494,8 +521,8 @@ class MediaDataManager(
}
/**
- * Called whenever the player has been paused or stopped for a while, or swiped from QQS.
- * This will make the player not active anymore, hiding it from QQS and Keyguard.
+ * Called whenever the player has been paused or stopped for a while, or swiped from QQS. This
+ * will make the player not active anymore, hiding it from QQS and Keyguard.
* @see MediaData.active
*/
internal fun setTimedOut(key: String, timedOut: Boolean, forceUpdate: Boolean = false) {
@@ -517,9 +544,7 @@ class MediaDataManager(
}
}
- /**
- * Called when the player's [PlaybackState] has been updated with new actions and/or state
- */
+ /** Called when the player's [PlaybackState] has been updated with new actions and/or state */
private fun updateState(key: String, state: PlaybackState) {
mediaEntries.get(key)?.let {
val token = it.token
@@ -527,22 +552,23 @@ class MediaDataManager(
if (DEBUG) Log.d(TAG, "State updated, but token was null")
return
}
- val actions = createActionsFromState(it.packageName,
- mediaControllerFactory.create(it.token), UserHandle(it.userId))
+ val actions =
+ createActionsFromState(
+ it.packageName,
+ mediaControllerFactory.create(it.token),
+ UserHandle(it.userId)
+ )
// Control buttons
// If flag is enabled and controller has a PlaybackState,
// create actions from session info
// otherwise, no need to update semantic actions.
- val data = if (actions != null) {
- it.copy(
- semanticActions = actions,
- isPlaying = isPlayingState(state.state))
- } else {
- it.copy(
- isPlaying = isPlayingState(state.state)
- )
- }
+ val data =
+ if (actions != null) {
+ it.copy(semanticActions = actions, isPlaying = isPlayingState(state.state))
+ } else {
+ it.copy(isPlaying = isPlayingState(state.state))
+ }
if (DEBUG) Log.d(TAG, "State updated outside of notification")
onMediaDataLoaded(key, key, data)
}
@@ -555,9 +581,7 @@ class MediaDataManager(
notifyMediaDataRemoved(key)
}
- /**
- * Dismiss a media entry. Returns false if the key was not found.
- */
+ /** Dismiss a media entry. Returns false if the key was not found. */
fun dismissMediaData(key: String, delay: Long): Boolean {
val existed = mediaEntries[key] != null
backgroundExecutor.execute {
@@ -575,9 +599,8 @@ class MediaDataManager(
}
/**
- * Called whenever the recommendation has been expired, or swiped from QQS.
- * This will make the recommendation view to not be shown anymore during this headphone
- * connection session.
+ * Called whenever the recommendation has been expired, or swiped from QQS. This will make the
+ * recommendation view to not be shown anymore during this headphone connection session.
*/
fun dismissSmartspaceRecommendation(key: String, delay: Long) {
if (smartspaceMediaData.targetId != key || !smartspaceMediaData.isValid()) {
@@ -587,13 +610,16 @@ class MediaDataManager(
if (DEBUG) Log.d(TAG, "Dismissing Smartspace media target")
if (smartspaceMediaData.isActive) {
- smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
- targetId = smartspaceMediaData.targetId,
- instanceId = smartspaceMediaData.instanceId)
+ smartspaceMediaData =
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ targetId = smartspaceMediaData.targetId,
+ instanceId = smartspaceMediaData.instanceId
+ )
}
foregroundExecutor.executeDelayed(
- { notifySmartspaceMediaDataRemoved(
- smartspaceMediaData.targetId, immediately = true) }, delay)
+ { notifySmartspaceMediaDataRemoved(smartspaceMediaData.targetId, immediately = true) },
+ delay
+ )
}
private fun loadMediaDataInBgForResumption(
@@ -621,11 +647,12 @@ class MediaDataManager(
if (artworkBitmap == null && desc.iconUri != null) {
artworkBitmap = loadBitmapFromUri(desc.iconUri!!)
}
- val artworkIcon = if (artworkBitmap != null) {
- Icon.createWithBitmap(artworkBitmap)
- } else {
- null
- }
+ val artworkIcon =
+ if (artworkBitmap != null) {
+ Icon.createWithBitmap(artworkBitmap)
+ } else {
+ null
+ }
val currentEntry = mediaEntries.get(packageName)
val instanceId = currentEntry?.instanceId ?: logger.getNewInstanceId()
@@ -634,13 +661,34 @@ class MediaDataManager(
val mediaAction = getResumeMediaAction(resumeAction)
val lastActive = systemClock.elapsedRealtime()
foregroundExecutor.execute {
- onMediaDataLoaded(packageName, null, MediaData(userId, true, appName,
- null, desc.subtitle, desc.title, artworkIcon, listOf(mediaAction), listOf(0),
- MediaButton(playOrPause = mediaAction), packageName, token, appIntent,
- device = null, active = false,
- resumeAction = resumeAction, resumption = true, notificationKey = packageName,
- hasCheckedForResume = true, lastActive = lastActive, instanceId = instanceId,
- appUid = appUid))
+ onMediaDataLoaded(
+ packageName,
+ null,
+ MediaData(
+ userId,
+ true,
+ appName,
+ null,
+ desc.subtitle,
+ desc.title,
+ artworkIcon,
+ listOf(mediaAction),
+ listOf(0),
+ MediaButton(playOrPause = mediaAction),
+ packageName,
+ token,
+ appIntent,
+ device = null,
+ active = false,
+ resumeAction = resumeAction,
+ resumption = true,
+ notificationKey = packageName,
+ hasCheckedForResume = true,
+ lastActive = lastActive,
+ instanceId = instanceId,
+ appUid = appUid
+ )
+ )
}
}
@@ -650,8 +698,11 @@ class MediaDataManager(
oldKey: String?,
logEvent: Boolean = false
) {
- val token = sbn.notification.extras.getParcelable(
- Notification.EXTRA_MEDIA_SESSION, MediaSession.Token::class.java)
+ val token =
+ sbn.notification.extras.getParcelable(
+ Notification.EXTRA_MEDIA_SESSION,
+ MediaSession.Token::class.java
+ )
if (token == null) {
return
}
@@ -659,10 +710,12 @@ class MediaDataManager(
val metadata = mediaController.metadata
val notif: Notification = sbn.notification
- val appInfo = notif.extras.getParcelable(
- Notification.EXTRA_BUILDER_APPLICATION_INFO,
- ApplicationInfo::class.java
- ) ?: getAppInfoFromPackage(sbn.packageName)
+ val appInfo =
+ notif.extras.getParcelable(
+ Notification.EXTRA_BUILDER_APPLICATION_INFO,
+ ApplicationInfo::class.java
+ )
+ ?: getAppInfoFromPackage(sbn.packageName)
// Album art
var artworkBitmap = metadata?.let { loadBitmapFromUri(it) }
@@ -672,11 +725,12 @@ class MediaDataManager(
if (artworkBitmap == null) {
artworkBitmap = metadata?.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)
}
- val artWorkIcon = if (artworkBitmap == null) {
- notif.getLargeIcon()
- } else {
- Icon.createWithBitmap(artworkBitmap)
- }
+ val artWorkIcon =
+ if (artworkBitmap == null) {
+ notif.getLargeIcon()
+ } else {
+ Icon.createWithBitmap(artworkBitmap)
+ }
// App name
val appName = getAppName(sbn, appInfo)
@@ -705,17 +759,27 @@ class MediaDataManager(
val extras = sbn.notification.extras
val deviceName = extras.getCharSequence(Notification.EXTRA_MEDIA_REMOTE_DEVICE, null)
val deviceIcon = extras.getInt(Notification.EXTRA_MEDIA_REMOTE_ICON, -1)
- val deviceIntent = extras.getParcelable(
- Notification.EXTRA_MEDIA_REMOTE_INTENT, PendingIntent::class.java)
+ val deviceIntent =
+ extras.getParcelable(
+ Notification.EXTRA_MEDIA_REMOTE_INTENT,
+ PendingIntent::class.java
+ )
Log.d(TAG, "$key is RCN for $deviceName")
if (deviceName != null && deviceIcon > -1) {
// Name and icon must be present, but intent may be null
val enabled = deviceIntent != null && deviceIntent.isActivity
- val deviceDrawable = Icon.createWithResource(sbn.packageName, deviceIcon)
+ val deviceDrawable =
+ Icon.createWithResource(sbn.packageName, deviceIcon)
.loadDrawable(sbn.getPackageContext(context))
- device = MediaDeviceData(enabled, deviceDrawable, deviceName, deviceIntent,
- showBroadcastButton = false)
+ device =
+ MediaDeviceData(
+ enabled,
+ deviceDrawable,
+ deviceName,
+ deviceIntent,
+ showBroadcastButton = false
+ )
}
}
@@ -732,10 +796,13 @@ class MediaDataManager(
}
val playbackLocation =
- if (isRemoteCastNotification(sbn)) MediaData.PLAYBACK_CAST_REMOTE
- else if (mediaController.playbackInfo?.playbackType ==
- MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL) MediaData.PLAYBACK_LOCAL
- else MediaData.PLAYBACK_CAST_LOCAL
+ if (isRemoteCastNotification(sbn)) MediaData.PLAYBACK_CAST_REMOTE
+ else if (
+ mediaController.playbackInfo?.playbackType ==
+ MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
+ )
+ MediaData.PLAYBACK_LOCAL
+ else MediaData.PLAYBACK_CAST_LOCAL
val isPlaying = mediaController.playbackState?.let { isPlayingState(it.state) } ?: null
val currentEntry = mediaEntries.get(key)
@@ -753,13 +820,36 @@ class MediaDataManager(
val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true
val active = mediaEntries[key]?.active ?: true
- onMediaDataLoaded(key, oldKey, MediaData(sbn.normalizedUserId, true, appName,
- smallIcon, artist, song, artWorkIcon, actionIcons, actionsToShowCollapsed,
- semanticActions, sbn.packageName, token, notif.contentIntent, device,
- active, resumeAction = resumeAction, playbackLocation = playbackLocation,
- notificationKey = key, hasCheckedForResume = hasCheckedForResume,
- isPlaying = isPlaying, isClearable = sbn.isClearable(),
- lastActive = lastActive, instanceId = instanceId, appUid = appUid))
+ onMediaDataLoaded(
+ key,
+ oldKey,
+ MediaData(
+ sbn.normalizedUserId,
+ true,
+ appName,
+ smallIcon,
+ artist,
+ song,
+ artWorkIcon,
+ actionIcons,
+ actionsToShowCollapsed,
+ semanticActions,
+ sbn.packageName,
+ token,
+ notif.contentIntent,
+ device,
+ active,
+ resumeAction = resumeAction,
+ playbackLocation = playbackLocation,
+ notificationKey = key,
+ hasCheckedForResume = hasCheckedForResume,
+ isPlaying = isPlaying,
+ isClearable = sbn.isClearable(),
+ lastActive = lastActive,
+ instanceId = instanceId,
+ appUid = appUid
+ )
+ )
}
}
@@ -785,27 +875,33 @@ class MediaDataManager(
}
}
- /**
- * Generate action buttons based on notification actions
- */
- private fun createActionsFromNotification(sbn: StatusBarNotification):
- Pair<List<MediaAction>, List<Int>> {
+ /** Generate action buttons based on notification actions */
+ private fun createActionsFromNotification(
+ sbn: StatusBarNotification
+ ): Pair<List<MediaAction>, List<Int>> {
val notif = sbn.notification
val actionIcons: MutableList<MediaAction> = ArrayList()
val actions = notif.actions
- var actionsToShowCollapsed = notif.extras.getIntArray(
- Notification.EXTRA_COMPACT_ACTIONS)?.toMutableList() ?: mutableListOf()
+ var actionsToShowCollapsed =
+ notif.extras.getIntArray(Notification.EXTRA_COMPACT_ACTIONS)?.toMutableList()
+ ?: mutableListOf()
if (actionsToShowCollapsed.size > MAX_COMPACT_ACTIONS) {
- Log.e(TAG, "Too many compact actions for ${sbn.key}," +
- "limiting to first $MAX_COMPACT_ACTIONS")
+ Log.e(
+ TAG,
+ "Too many compact actions for ${sbn.key}," +
+ "limiting to first $MAX_COMPACT_ACTIONS"
+ )
actionsToShowCollapsed = actionsToShowCollapsed.subList(0, MAX_COMPACT_ACTIONS)
}
if (actions != null) {
for ((index, action) in actions.withIndex()) {
if (index == MAX_NOTIFICATION_ACTIONS) {
- Log.w(TAG, "Too many notification actions for ${sbn.key}," +
- " limiting to first $MAX_NOTIFICATION_ACTIONS")
+ Log.w(
+ TAG,
+ "Too many notification actions for ${sbn.key}," +
+ " limiting to first $MAX_NOTIFICATION_ACTIONS"
+ )
break
}
if (action.getIcon() == null) {
@@ -813,33 +909,38 @@ class MediaDataManager(
actionsToShowCollapsed.remove(index)
continue
}
- val runnable = if (action.actionIntent != null) {
- Runnable {
- if (action.actionIntent.isActivity) {
- activityStarter.startPendingIntentDismissingKeyguard(
- action.actionIntent)
- } else if (action.isAuthenticationRequired()) {
- activityStarter.dismissKeyguardThenExecute({
- var result = sendPendingIntent(action.actionIntent)
- result
- }, {}, true)
- } else {
- sendPendingIntent(action.actionIntent)
+ val runnable =
+ if (action.actionIntent != null) {
+ Runnable {
+ if (action.actionIntent.isActivity) {
+ activityStarter.startPendingIntentDismissingKeyguard(
+ action.actionIntent
+ )
+ } else if (action.isAuthenticationRequired()) {
+ activityStarter.dismissKeyguardThenExecute(
+ {
+ var result = sendPendingIntent(action.actionIntent)
+ result
+ },
+ {},
+ true
+ )
+ } else {
+ sendPendingIntent(action.actionIntent)
+ }
}
+ } else {
+ null
}
- } else {
- null
- }
- val mediaActionIcon = if (action.getIcon()?.getType() == Icon.TYPE_RESOURCE) {
- Icon.createWithResource(sbn.packageName, action.getIcon()!!.getResId())
- } else {
- action.getIcon()
- }.setTint(themeText).loadDrawable(context)
- val mediaAction = MediaAction(
- mediaActionIcon,
- runnable,
- action.title,
- null)
+ val mediaActionIcon =
+ if (action.getIcon()?.getType() == Icon.TYPE_RESOURCE) {
+ Icon.createWithResource(sbn.packageName, action.getIcon()!!.getResId())
+ } else {
+ action.getIcon()
+ }
+ .setTint(themeText)
+ .loadDrawable(context)
+ val mediaAction = MediaAction(mediaActionIcon, runnable, action.title, null)
actionIcons.add(mediaAction)
}
}
@@ -852,7 +953,9 @@ class MediaDataManager(
* @param packageName Package name for the media app
* @param controller MediaController for the current session
* @return a Pair consisting of a list of media actions, and a list of ints representing which
+ * ```
* of those actions should be shown in the compact player
+ * ```
*/
private fun createActionsFromState(
packageName: String,
@@ -865,59 +968,69 @@ class MediaDataManager(
}
// First, check for standard actions
- val playOrPause = if (isConnectingState(state.state)) {
- // Spinner needs to be animating to render anything. Start it here.
- val drawable = context.getDrawable(
- com.android.internal.R.drawable.progress_small_material)
- (drawable as Animatable).start()
- MediaAction(
- drawable,
- null, // no action to perform when clicked
- context.getString(R.string.controls_media_button_connecting),
- context.getDrawable(R.drawable.ic_media_connecting_container),
- // Specify a rebind id to prevent the spinner from restarting on later binds.
- com.android.internal.R.drawable.progress_small_material
- )
- } else if (isPlayingState(state.state)) {
- getStandardAction(controller, state.actions, PlaybackState.ACTION_PAUSE)
- } else {
- getStandardAction(controller, state.actions, PlaybackState.ACTION_PLAY)
- }
- val prevButton = getStandardAction(controller, state.actions,
- PlaybackState.ACTION_SKIP_TO_PREVIOUS)
- val nextButton = getStandardAction(controller, state.actions,
- PlaybackState.ACTION_SKIP_TO_NEXT)
+ val playOrPause =
+ if (isConnectingState(state.state)) {
+ // Spinner needs to be animating to render anything. Start it here.
+ val drawable =
+ context.getDrawable(com.android.internal.R.drawable.progress_small_material)
+ (drawable as Animatable).start()
+ MediaAction(
+ drawable,
+ null, // no action to perform when clicked
+ context.getString(R.string.controls_media_button_connecting),
+ context.getDrawable(R.drawable.ic_media_connecting_container),
+ // Specify a rebind id to prevent the spinner from restarting on later binds.
+ com.android.internal.R.drawable.progress_small_material
+ )
+ } else if (isPlayingState(state.state)) {
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_PAUSE)
+ } else {
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_PLAY)
+ }
+ val prevButton =
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_SKIP_TO_PREVIOUS)
+ val nextButton =
+ getStandardAction(controller, state.actions, PlaybackState.ACTION_SKIP_TO_NEXT)
// Then, create a way to build any custom actions that will be needed
- val customActions = state.customActions.asSequence().filterNotNull().map {
- getCustomAction(state, packageName, controller, it)
- }.iterator()
+ val customActions =
+ state.customActions
+ .asSequence()
+ .filterNotNull()
+ .map { getCustomAction(state, packageName, controller, it) }
+ .iterator()
fun nextCustomAction() = if (customActions.hasNext()) customActions.next() else null
// Finally, assign the remaining button slots: play/pause A B C D
// A = previous, else custom action (if not reserved)
// B = next, else custom action (if not reserved)
// C and D are always custom actions
- val reservePrev = controller.extras?.getBoolean(
- MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV) == true
- val reserveNext = controller.extras?.getBoolean(
- MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT) == true
-
- val prevOrCustom = if (prevButton != null) {
- prevButton
- } else if (!reservePrev) {
- nextCustomAction()
- } else {
- null
- }
+ val reservePrev =
+ controller.extras?.getBoolean(
+ MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
+ ) == true
+ val reserveNext =
+ controller.extras?.getBoolean(
+ MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
+ ) == true
+
+ val prevOrCustom =
+ if (prevButton != null) {
+ prevButton
+ } else if (!reservePrev) {
+ nextCustomAction()
+ } else {
+ null
+ }
- val nextOrCustom = if (nextButton != null) {
- nextButton
- } else if (!reserveNext) {
- nextCustomAction()
- } else {
- null
- }
+ val nextOrCustom =
+ if (nextButton != null) {
+ nextButton
+ } else if (!reserveNext) {
+ nextCustomAction()
+ } else {
+ null
+ }
return MediaButton(
playOrPause,
@@ -936,11 +1049,14 @@ class MediaDataManager(
* @param controller MediaController for the session
* @param stateActions The actions included with the session's [PlaybackState]
* @param action A [PlaybackState.Actions] value representing what action to generate. One of:
+ * ```
* [PlaybackState.ACTION_PLAY]
* [PlaybackState.ACTION_PAUSE]
* [PlaybackState.ACTION_SKIP_TO_PREVIOUS]
* [PlaybackState.ACTION_SKIP_TO_NEXT]
- * @return A [MediaAction] with correct values set, or null if the state doesn't support it
+ * @return
+ * ```
+ * A [MediaAction] with correct values set, or null if the state doesn't support it
*/
private fun getStandardAction(
controller: MediaController,
@@ -988,20 +1104,18 @@ class MediaDataManager(
}
}
- /**
- * Check whether the actions from a [PlaybackState] include a specific action
- */
+ /** Check whether the actions from a [PlaybackState] include a specific action */
private fun includesAction(stateActions: Long, @PlaybackState.Actions action: Long): Boolean {
- if ((action == PlaybackState.ACTION_PLAY || action == PlaybackState.ACTION_PAUSE) &&
- (stateActions and PlaybackState.ACTION_PLAY_PAUSE > 0L)) {
+ if (
+ (action == PlaybackState.ACTION_PLAY || action == PlaybackState.ACTION_PAUSE) &&
+ (stateActions and PlaybackState.ACTION_PLAY_PAUSE > 0L)
+ ) {
return true
}
return (stateActions and action != 0L)
}
- /**
- * Get a [MediaAction] representing a [PlaybackState.CustomAction]
- */
+ /** Get a [MediaAction] representing a [PlaybackState.CustomAction] */
private fun getCustomAction(
state: PlaybackState,
packageName: String,
@@ -1016,9 +1130,7 @@ class MediaDataManager(
)
}
- /**
- * Load a bitmap from the various Art metadata URIs
- */
+ /** Load a bitmap from the various Art metadata URIs */
private fun loadBitmapFromUri(metadata: MediaMetadata): Bitmap? {
for (uri in ART_URIS) {
val uriString = metadata.getString(uri)
@@ -1053,16 +1165,18 @@ class MediaDataManager(
return null
}
- if (!uri.scheme.equals(ContentResolver.SCHEME_CONTENT) &&
+ if (
+ !uri.scheme.equals(ContentResolver.SCHEME_CONTENT) &&
!uri.scheme.equals(ContentResolver.SCHEME_ANDROID_RESOURCE) &&
- !uri.scheme.equals(ContentResolver.SCHEME_FILE)) {
+ !uri.scheme.equals(ContentResolver.SCHEME_FILE)
+ ) {
return null
}
val source = ImageDecoder.createSource(context.getContentResolver(), uri)
return try {
- ImageDecoder.decodeBitmap(source) {
- decoder, info, source -> decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
+ ImageDecoder.decodeBitmap(source) { decoder, _, _ ->
+ decoder.allocator = ImageDecoder.ALLOCATOR_SOFTWARE
}
} catch (e: IOException) {
Log.e(TAG, "Unable to load bitmap", e)
@@ -1076,25 +1190,23 @@ class MediaDataManager(
private fun getResumeMediaAction(action: Runnable): MediaAction {
return MediaAction(
Icon.createWithResource(context, R.drawable.ic_media_play)
- .setTint(themeText).loadDrawable(context),
+ .setTint(themeText)
+ .loadDrawable(context),
action,
context.getString(R.string.controls_media_resume),
context.getDrawable(R.drawable.ic_media_play_container)
)
}
- fun onMediaDataLoaded(
- key: String,
- oldKey: String?,
- data: MediaData
- ) = traceSection("MediaDataManager#onMediaDataLoaded") {
- Assert.isMainThread()
- if (mediaEntries.containsKey(key)) {
- // Otherwise this was removed already
- mediaEntries.put(key, data)
- notifyMediaDataLoaded(key, oldKey, data)
+ fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) =
+ traceSection("MediaDataManager#onMediaDataLoaded") {
+ Assert.isMainThread()
+ if (mediaEntries.containsKey(key)) {
+ // Otherwise this was removed already
+ mediaEntries.put(key, data)
+ notifyMediaDataLoaded(key, oldKey, data)
+ }
}
- }
override fun onSmartspaceTargetsUpdated(targets: List<Parcelable>) {
if (!allowMediaRecommendations) {
@@ -1111,9 +1223,11 @@ class MediaDataManager(
if (DEBUG) {
Log.d(TAG, "Set Smartspace media to be inactive for the data update")
}
- smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
- targetId = smartspaceMediaData.targetId,
- instanceId = smartspaceMediaData.instanceId)
+ smartspaceMediaData =
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ targetId = smartspaceMediaData.targetId,
+ instanceId = smartspaceMediaData.instanceId
+ )
notifySmartspaceMediaDataRemoved(smartspaceMediaData.targetId, immediately = false)
}
1 -> {
@@ -1124,15 +1238,16 @@ class MediaDataManager(
}
if (DEBUG) Log.d(TAG, "Forwarding Smartspace media update.")
smartspaceMediaData = toSmartspaceMediaData(newMediaTarget, isActive = true)
- notifySmartspaceMediaDataLoaded(
- smartspaceMediaData.targetId, smartspaceMediaData)
+ notifySmartspaceMediaDataLoaded(smartspaceMediaData.targetId, smartspaceMediaData)
}
else -> {
// There should NOT be more than 1 Smartspace media update. When it happens, it
// indicates a bad state or an error. Reset the status accordingly.
Log.wtf(TAG, "More than 1 Smartspace Media Update. Resetting the status...")
notifySmartspaceMediaDataRemoved(
- smartspaceMediaData.targetId, false /* immediately */)
+ smartspaceMediaData.targetId,
+ false /* immediately */
+ )
smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA
}
}
@@ -1145,10 +1260,17 @@ class MediaDataManager(
Log.d(TAG, "Not removing $key because resumable")
// Move to resume key (aka package name) if that key doesn't already exist.
val resumeAction = getResumeMediaAction(removed.resumeAction!!)
- val updated = removed.copy(token = null, actions = listOf(resumeAction),
+ val updated =
+ removed.copy(
+ token = null,
+ actions = listOf(resumeAction),
semanticActions = MediaButton(playOrPause = resumeAction),
- actionsToShowInCompact = listOf(0), active = false, resumption = true,
- isPlaying = false, isClearable = true)
+ actionsToShowInCompact = listOf(0),
+ active = false,
+ resumption = true,
+ isPlaying = false,
+ isClearable = true
+ )
val pkg = removed.packageName
val migrate = mediaEntries.put(pkg, updated) == null
// Notify listeners of "new" controls when migrating or removed and update when not
@@ -1190,33 +1312,27 @@ class MediaDataManager(
}
}
- /**
- * Invoked when the user has dismissed the media carousel
- */
+ /** Invoked when the user has dismissed the media carousel */
fun onSwipeToDismiss() = mediaDataFilter.onSwipeToDismiss()
- /**
- * Are there any media notifications active, including the recommendations?
- */
+ /** Are there any media notifications active, including the recommendations? */
fun hasActiveMediaOrRecommendation() = mediaDataFilter.hasActiveMediaOrRecommendation()
/**
* Are there any media entries we should display, including the recommendations?
- * If resumption is enabled, this will include inactive players
- * If resumption is disabled, we only want to show active players
+ * - If resumption is enabled, this will include inactive players
+ * - If resumption is disabled, we only want to show active players
*/
fun hasAnyMediaOrRecommendation() = mediaDataFilter.hasAnyMediaOrRecommendation()
- /**
- * Are there any resume media notifications active, excluding the recommendations?
- */
+ /** Are there any resume media notifications active, excluding the recommendations? */
fun hasActiveMedia() = mediaDataFilter.hasActiveMedia()
/**
- * Are there any resume media notifications active, excluding the recommendations?
- * If resumption is enabled, this will include inactive players
- * If resumption is disabled, we only want to show active players
- */
+ * Are there any resume media notifications active, excluding the recommendations?
+ * - If resumption is enabled, this will include inactive players
+ * - If resumption is disabled, we only want to show active players
+ */
fun hasAnyMedia() = mediaDataFilter.hasAnyMedia()
interface Listener {
@@ -1286,10 +1402,9 @@ class MediaDataManager(
): SmartspaceMediaData {
var dismissIntent: Intent? = null
if (target.baseAction != null && target.baseAction.extras != null) {
- dismissIntent = target
- .baseAction
- .extras
- .getParcelable(EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY) as Intent?
+ dismissIntent =
+ target.baseAction.extras.getParcelable(EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY)
+ as Intent?
}
packageName(target)?.let {
return SmartspaceMediaData(
@@ -1300,14 +1415,16 @@ class MediaDataManager(
recommendations = target.iconGrid,
dismissIntent = dismissIntent,
headphoneConnectionTimeMillis = target.creationTimeMillis,
- instanceId = logger.getNewInstanceId())
+ instanceId = logger.getNewInstanceId()
+ )
}
- return EMPTY_SMARTSPACE_MEDIA_DATA
- .copy(targetId = target.smartspaceTargetId,
- isActive = isActive,
- dismissIntent = dismissIntent,
- headphoneConnectionTimeMillis = target.creationTimeMillis,
- instanceId = logger.getNewInstanceId())
+ return EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ targetId = target.smartspaceTargetId,
+ isActive = isActive,
+ dismissIntent = dismissIntent,
+ headphoneConnectionTimeMillis = target.creationTimeMillis,
+ instanceId = logger.getNewInstanceId()
+ )
}
private fun packageName(target: SmartspaceTarget): String? {
@@ -1319,8 +1436,9 @@ class MediaDataManager(
for (recommendation in recommendationList) {
val extras = recommendation.extras
extras?.let {
- it.getString(EXTRAS_MEDIA_SOURCE_PACKAGE_NAME)?.let {
- packageName -> return packageName }
+ it.getString(EXTRAS_MEDIA_SOURCE_PACKAGE_NAME)?.let { packageName ->
+ return packageName
+ }
}
}
Log.w(TAG, "No valid package name is provided.")
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
index af1d6cf340b7..6a512be091e1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDeviceManager.kt
@@ -36,10 +36,10 @@ import com.android.systemui.R
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
-import com.android.systemui.media.controls.util.MediaControllerFactory
-import com.android.systemui.media.controls.util.MediaDataUtils
import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.models.player.MediaDeviceData
+import com.android.systemui.media.controls.util.MediaControllerFactory
+import com.android.systemui.media.controls.util.MediaDataUtils
import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager
import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManagerFactory
import com.android.systemui.statusbar.policy.ConfigurationController
@@ -51,10 +51,10 @@ private const val PLAYBACK_TYPE_UNKNOWN = 0
private const val TAG = "MediaDeviceManager"
private const val DEBUG = true
-/**
- * Provides information about the route (ie. device) where playback is occurring.
- */
-class MediaDeviceManager @Inject constructor(
+/** Provides information about the route (ie. device) where playback is occurring. */
+class MediaDeviceManager
+@Inject
+constructor(
private val context: Context,
private val controllerFactory: MediaControllerFactory,
private val localMediaManagerFactory: LocalMediaManagerFactory,
@@ -74,14 +74,10 @@ class MediaDeviceManager @Inject constructor(
dumpManager.registerDumpable(javaClass.name, this)
}
- /**
- * Add a listener for changes to the media route (ie. device).
- */
+ /** Add a listener for changes to the media route (ie. device). */
fun addListener(listener: Listener) = listeners.add(listener)
- /**
- * Remove a listener that has been registered with addListener.
- */
+ /** Remove a listener that has been registered with addListener. */
fun removeListener(listener: Listener) = listeners.remove(listener)
override fun onMediaDataLoaded(
@@ -105,19 +101,11 @@ class MediaDeviceManager @Inject constructor(
processDevice(key, oldKey, data.device)
return
}
- val controller = data.token?.let {
- controllerFactory.create(it)
- }
+ val controller = data.token?.let { controllerFactory.create(it) }
val localMediaManager = localMediaManagerFactory.create(data.packageName)
val muteAwaitConnectionManager =
- muteAwaitConnectionManagerFactory.create(localMediaManager)
- entry = Entry(
- key,
- oldKey,
- controller,
- localMediaManager,
- muteAwaitConnectionManager
- )
+ muteAwaitConnectionManagerFactory.create(localMediaManager)
+ entry = Entry(key, oldKey, controller, localMediaManager, muteAwaitConnectionManager)
entries[key] = entry
entry.start()
}
@@ -126,11 +114,7 @@ class MediaDeviceManager @Inject constructor(
override fun onMediaDataRemoved(key: String) {
val token = entries.remove(key)
token?.stop()
- token?.let {
- listeners.forEach {
- it.onKeyRemoved(key)
- }
- }
+ token?.let { listeners.forEach { it.onKeyRemoved(key) } }
}
override fun dump(pw: PrintWriter, args: Array<String>) {
@@ -145,9 +129,7 @@ class MediaDeviceManager @Inject constructor(
@MainThread
private fun processDevice(key: String, oldKey: String?, device: MediaDeviceData?) {
- listeners.forEach {
- it.onMediaDeviceChanged(key, oldKey, device)
- }
+ listeners.forEach { it.onMediaDeviceChanged(key, oldKey, device) }
}
interface Listener {
@@ -163,8 +145,10 @@ class MediaDeviceManager @Inject constructor(
val controller: MediaController?,
val localMediaManager: LocalMediaManager,
val muteAwaitConnectionManager: MediaMuteAwaitConnectionManager?
- ) : LocalMediaManager.DeviceCallback, MediaController.Callback(),
- BluetoothLeBroadcast.Callback {
+ ) :
+ LocalMediaManager.DeviceCallback,
+ MediaController.Callback(),
+ BluetoothLeBroadcast.Callback {
val token
get() = controller?.sessionToken
@@ -175,54 +159,52 @@ class MediaDeviceManager @Inject constructor(
val sameWithoutIcon = value != null && value.equalsWithoutIcon(field)
if (!started || !sameWithoutIcon) {
field = value
- fgExecutor.execute {
- processDevice(key, oldKey, value)
- }
+ fgExecutor.execute { processDevice(key, oldKey, value) }
}
}
// A device that is not yet connected but is expected to connect imminently. Because it's
// expected to connect imminently, it should be displayed as the current device.
private var aboutToConnectDeviceOverride: AboutToConnectDevice? = null
private var broadcastDescription: String? = null
- private val configListener = object : ConfigurationController.ConfigurationListener {
- override fun onLocaleListChanged() {
- updateCurrent()
+ private val configListener =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onLocaleListChanged() {
+ updateCurrent()
+ }
}
- }
@AnyThread
- fun start() = bgExecutor.execute {
- if (!started) {
- localMediaManager.registerCallback(this)
- localMediaManager.startScan()
- muteAwaitConnectionManager?.startListening()
- playbackType = controller?.playbackInfo?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
- controller?.registerCallback(this)
- updateCurrent()
- started = true
- configurationController.addCallback(configListener)
+ fun start() =
+ bgExecutor.execute {
+ if (!started) {
+ localMediaManager.registerCallback(this)
+ localMediaManager.startScan()
+ muteAwaitConnectionManager?.startListening()
+ playbackType = controller?.playbackInfo?.playbackType ?: PLAYBACK_TYPE_UNKNOWN
+ controller?.registerCallback(this)
+ updateCurrent()
+ started = true
+ configurationController.addCallback(configListener)
+ }
}
- }
@AnyThread
- fun stop() = bgExecutor.execute {
- if (started) {
- started = false
- controller?.unregisterCallback(this)
- localMediaManager.stopScan()
- localMediaManager.unregisterCallback(this)
- muteAwaitConnectionManager?.stopListening()
- configurationController.removeCallback(configListener)
+ fun stop() =
+ bgExecutor.execute {
+ if (started) {
+ started = false
+ controller?.unregisterCallback(this)
+ localMediaManager.stopScan()
+ localMediaManager.unregisterCallback(this)
+ muteAwaitConnectionManager?.stopListening()
+ configurationController.removeCallback(configListener)
+ }
}
- }
fun dump(pw: PrintWriter) {
- val routingSession = controller?.let {
- mr2manager.getRoutingSessionForMediaController(it)
- }
- val selectedRoutes = routingSession?.let {
- mr2manager.getSelectedRoutes(it)
- }
+ val routingSession =
+ controller?.let { mr2manager.getRoutingSessionForMediaController(it) }
+ val selectedRoutes = routingSession?.let { mr2manager.getSelectedRoutes(it) }
with(pw) {
println(" current device is ${current?.name}")
val type = controller?.playbackInfo?.playbackType
@@ -242,14 +224,11 @@ class MediaDeviceManager @Inject constructor(
updateCurrent()
}
- override fun onDeviceListUpdate(devices: List<MediaDevice>?) = bgExecutor.execute {
- updateCurrent()
- }
+ override fun onDeviceListUpdate(devices: List<MediaDevice>?) =
+ bgExecutor.execute { updateCurrent() }
override fun onSelectedDeviceStateChanged(device: MediaDevice, state: Int) {
- bgExecutor.execute {
- updateCurrent()
- }
+ bgExecutor.execute { updateCurrent() }
}
override fun onAboutToConnectDeviceAdded(
@@ -257,14 +236,17 @@ class MediaDeviceManager @Inject constructor(
deviceName: String,
deviceIcon: Drawable?
) {
- aboutToConnectDeviceOverride = AboutToConnectDevice(
- fullMediaDevice = localMediaManager.getMediaDeviceById(deviceAddress),
- backupMediaDeviceData = MediaDeviceData(
- /* enabled */ enabled = true,
- /* icon */ deviceIcon,
- /* name */ deviceName,
- /* showBroadcastButton */ showBroadcastButton = false)
- )
+ aboutToConnectDeviceOverride =
+ AboutToConnectDevice(
+ fullMediaDevice = localMediaManager.getMediaDeviceById(deviceAddress),
+ backupMediaDeviceData =
+ MediaDeviceData(
+ /* enabled */ enabled = true,
+ /* icon */ deviceIcon,
+ /* name */ deviceName,
+ /* showBroadcastButton */ showBroadcastButton = false
+ )
+ )
updateCurrent()
}
@@ -291,8 +273,11 @@ class MediaDeviceManager @Inject constructor(
metadata: BluetoothLeBroadcastMetadata
) {
if (DEBUG) {
- Log.d(TAG, "onBroadcastMetadataChanged(), broadcastId = $broadcastId , " +
- "metadata = $metadata")
+ Log.d(
+ TAG,
+ "onBroadcastMetadataChanged(), broadcastId = $broadcastId , " +
+ "metadata = $metadata"
+ )
}
updateCurrent()
}
@@ -319,8 +304,10 @@ class MediaDeviceManager @Inject constructor(
override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {
if (DEBUG) {
- Log.d(TAG, "onBroadcastUpdateFailed(), reason = $reason , " +
- "broadcastId = $broadcastId")
+ Log.d(
+ TAG,
+ "onBroadcastUpdateFailed(), reason = $reason , " + "broadcastId = $broadcastId"
+ )
}
}
@@ -331,34 +318,45 @@ class MediaDeviceManager @Inject constructor(
@WorkerThread
private fun updateCurrent() {
if (isLeAudioBroadcastEnabled()) {
- current = MediaDeviceData(
+ current =
+ MediaDeviceData(
/* enabled */ true,
/* icon */ context.getDrawable(R.drawable.settings_input_antenna),
/* name */ broadcastDescription,
/* intent */ null,
- /* showBroadcastButton */ showBroadcastButton = true)
+ /* showBroadcastButton */ showBroadcastButton = true
+ )
} else {
val aboutToConnect = aboutToConnectDeviceOverride
- if (aboutToConnect != null &&
+ if (
+ aboutToConnect != null &&
aboutToConnect.fullMediaDevice == null &&
- aboutToConnect.backupMediaDeviceData != null) {
+ aboutToConnect.backupMediaDeviceData != null
+ ) {
// Only use [backupMediaDeviceData] when we don't have [fullMediaDevice].
current = aboutToConnect.backupMediaDeviceData
return
}
- val device = aboutToConnect?.fullMediaDevice
- ?: localMediaManager.currentConnectedDevice
+ val device =
+ aboutToConnect?.fullMediaDevice ?: localMediaManager.currentConnectedDevice
val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it) }
// If we have a controller but get a null route, then don't trust the device
val enabled = device != null && (controller == null || route != null)
- val name = if (controller == null || route != null) {
- route?.name?.toString() ?: device?.name
- } else {
- null
- }
- current = MediaDeviceData(enabled, device?.iconWithoutBackground, name,
- id = device?.id, showBroadcastButton = false)
+ val name =
+ if (controller == null || route != null) {
+ route?.name?.toString() ?: device?.name
+ } else {
+ null
+ }
+ current =
+ MediaDeviceData(
+ enabled,
+ device?.iconWithoutBackground,
+ name,
+ id = device?.id,
+ showBroadcastButton = false
+ )
}
}
@@ -388,13 +386,16 @@ class MediaDeviceManager @Inject constructor(
// unexpected result.
// Check the current media app's name is the same with current broadcast app's name
// or not.
- var mediaApp = MediaDataUtils.getAppLabel(
- context, localMediaManager.packageName,
- context.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name))
+ var mediaApp =
+ MediaDataUtils.getAppLabel(
+ context,
+ localMediaManager.packageName,
+ context.getString(R.string.bt_le_audio_broadcast_dialog_unknown_name)
+ )
var isCurrentBroadcastedApp = TextUtils.equals(mediaApp, currentBroadcastedApp)
if (isCurrentBroadcastedApp) {
- broadcastDescription = context.getString(
- R.string.broadcasting_description_is_broadcasting)
+ broadcastDescription =
+ context.getString(R.string.broadcasting_description_is_broadcasting)
} else {
broadcastDescription = currentBroadcastedApp
}
@@ -407,9 +408,9 @@ class MediaDeviceManager @Inject constructor(
* [LocalMediaManager.DeviceCallback.onAboutToConnectDeviceAdded] for more information.
*
* @property fullMediaDevice a full-fledged [MediaDevice] object representing the device. If
- * non-null, prefer using [fullMediaDevice] over [backupMediaDeviceData].
+ * non-null, prefer using [fullMediaDevice] over [backupMediaDeviceData].
* @property backupMediaDeviceData a backup [MediaDeviceData] object containing the minimum
- * information required to display the device. Only use if [fullMediaDevice] is null.
+ * information required to display the device. Only use if [fullMediaDevice] is null.
*/
private data class AboutToConnectDevice(
val fullMediaDevice: MediaDevice? = null,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaSessionBasedFilter.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaSessionBasedFilter.kt
index ebf7be8af679..ab93b292308e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaSessionBasedFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaSessionBasedFilter.kt
@@ -40,7 +40,9 @@ private const val TAG = "MediaSessionBasedFilter"
* sessions. In this situation, there should only be a media object for the remote session. To
* achieve this, update events for the local session need to be filtered.
*/
-class MediaSessionBasedFilter @Inject constructor(
+class MediaSessionBasedFilter
+@Inject
+constructor(
context: Context,
private val sessionManager: MediaSessionManager,
@Main private val foregroundExecutor: Executor,
@@ -52,7 +54,7 @@ class MediaSessionBasedFilter @Inject constructor(
// Keep track of MediaControllers for a given package to check if an app is casting and it
// filter loaded events for local sessions.
private val packageControllers: LinkedHashMap<String, MutableList<MediaController>> =
- LinkedHashMap()
+ LinkedHashMap()
// Keep track of the key used for the session tokens. This information is used to know when to
// dispatch a removed event so that a media object for a local session will be removed.
@@ -61,11 +63,12 @@ class MediaSessionBasedFilter @Inject constructor(
// Keep track of which media session tokens have associated notifications.
private val tokensWithNotifications: MutableSet<MediaSession.Token> = mutableSetOf()
- private val sessionListener = object : MediaSessionManager.OnActiveSessionsChangedListener {
- override fun onActiveSessionsChanged(controllers: List<MediaController>) {
- handleControllersChanged(controllers)
+ private val sessionListener =
+ object : MediaSessionManager.OnActiveSessionsChangedListener {
+ override fun onActiveSessionsChanged(controllers: List<MediaController>) {
+ handleControllersChanged(controllers)
+ }
}
- }
init {
backgroundExecutor.execute {
@@ -75,14 +78,10 @@ class MediaSessionBasedFilter @Inject constructor(
}
}
- /**
- * Add a listener for filtered [MediaData] changes
- */
+ /** Add a listener for filtered [MediaData] changes */
fun addListener(listener: MediaDataManager.Listener) = listeners.add(listener)
- /**
- * Remove a listener that was registered with addListener
- */
+ /** Remove a listener that was registered with addListener */
fun removeListener(listener: MediaDataManager.Listener) = listeners.remove(listener)
/**
@@ -102,31 +101,32 @@ class MediaSessionBasedFilter @Inject constructor(
isSsReactivated: Boolean
) {
backgroundExecutor.execute {
- data.token?.let {
- tokensWithNotifications.add(it)
- }
+ data.token?.let { tokensWithNotifications.add(it) }
val isMigration = oldKey != null && key != oldKey
if (isMigration) {
keyedTokens.remove(oldKey)?.let { removed -> keyedTokens.put(key, removed) }
}
if (data.token != null) {
- keyedTokens.get(key)?.let {
- tokens ->
- tokens.add(data.token)
- } ?: run {
- val tokens = mutableSetOf(data.token)
- keyedTokens.put(key, tokens)
- }
+ keyedTokens.get(key)?.let { tokens -> tokens.add(data.token) }
+ ?: run {
+ val tokens = mutableSetOf(data.token)
+ keyedTokens.put(key, tokens)
+ }
}
// Determine if an app is casting by checking if it has a session with playback type
// PLAYBACK_TYPE_REMOTE.
- val remoteControllers = packageControllers.get(data.packageName)?.filter {
- it.playbackInfo?.playbackType == PlaybackInfo.PLAYBACK_TYPE_REMOTE
- }
+ val remoteControllers =
+ packageControllers.get(data.packageName)?.filter {
+ it.playbackInfo?.playbackType == PlaybackInfo.PLAYBACK_TYPE_REMOTE
+ }
// Limiting search to only apps with a single remote session.
val remote = if (remoteControllers?.size == 1) remoteControllers.firstOrNull() else null
- if (isMigration || remote == null || remote.sessionToken == data.token ||
- !tokensWithNotifications.contains(remote.sessionToken)) {
+ if (
+ isMigration ||
+ remote == null ||
+ remote.sessionToken == data.token ||
+ !tokensWithNotifications.contains(remote.sessionToken)
+ ) {
// Not filtering in this case. Passing the event along to listeners.
dispatchMediaDataLoaded(key, oldKey, data, immediately)
} else {
@@ -148,9 +148,7 @@ class MediaSessionBasedFilter @Inject constructor(
data: SmartspaceMediaData,
shouldPrioritize: Boolean
) {
- backgroundExecutor.execute {
- dispatchSmartspaceMediaDataLoaded(key, data)
- }
+ backgroundExecutor.execute { dispatchSmartspaceMediaDataLoaded(key, data) }
}
override fun onMediaDataRemoved(key: String) {
@@ -162,9 +160,7 @@ class MediaSessionBasedFilter @Inject constructor(
}
override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
- backgroundExecutor.execute {
- dispatchSmartspaceMediaDataRemoved(key, immediately)
- }
+ backgroundExecutor.execute { dispatchSmartspaceMediaDataRemoved(key, immediately) }
}
private fun dispatchMediaDataLoaded(
@@ -179,9 +175,7 @@ class MediaSessionBasedFilter @Inject constructor(
}
private fun dispatchMediaDataRemoved(key: String) {
- foregroundExecutor.execute {
- listeners.toSet().forEach { it.onMediaDataRemoved(key) }
- }
+ foregroundExecutor.execute { listeners.toSet().forEach { it.onMediaDataRemoved(key) } }
}
private fun dispatchSmartspaceMediaDataLoaded(key: String, info: SmartspaceMediaData) {
@@ -198,15 +192,12 @@ class MediaSessionBasedFilter @Inject constructor(
private fun handleControllersChanged(controllers: List<MediaController>) {
packageControllers.clear()
- controllers.forEach {
- controller ->
- packageControllers.get(controller.packageName)?.let {
- tokens ->
- tokens.add(controller)
- } ?: run {
- val tokens = mutableListOf(controller)
- packageControllers.put(controller.packageName, tokens)
- }
+ controllers.forEach { controller ->
+ packageControllers.get(controller.packageName)?.let { tokens -> tokens.add(controller) }
+ ?: run {
+ val tokens = mutableListOf(controller)
+ packageControllers.put(controller.packageName, tokens)
+ }
}
tokensWithNotifications.retainAll(controllers.map { it.sessionToken })
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt
index e29ab6d43519..7f5c82fb5eee 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListener.kt
@@ -22,8 +22,8 @@ import android.os.SystemProperties
import com.android.internal.annotations.VisibleForTesting
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.controls.util.MediaControllerFactory
import com.android.systemui.media.controls.models.player.MediaData
+import com.android.systemui.media.controls.util.MediaControllerFactory
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.NotificationMediaManager.isPlayingState
import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -33,18 +33,18 @@ import java.util.concurrent.TimeUnit
import javax.inject.Inject
@VisibleForTesting
-val PAUSED_MEDIA_TIMEOUT = SystemProperties
- .getLong("debug.sysui.media_timeout", TimeUnit.MINUTES.toMillis(10))
+val PAUSED_MEDIA_TIMEOUT =
+ SystemProperties.getLong("debug.sysui.media_timeout", TimeUnit.MINUTES.toMillis(10))
@VisibleForTesting
-val RESUME_MEDIA_TIMEOUT = SystemProperties
- .getLong("debug.sysui.media_timeout_resume", TimeUnit.DAYS.toMillis(3))
+val RESUME_MEDIA_TIMEOUT =
+ SystemProperties.getLong("debug.sysui.media_timeout_resume", TimeUnit.DAYS.toMillis(3))
-/**
- * Controller responsible for keeping track of playback states and expiring inactive streams.
- */
+/** Controller responsible for keeping track of playback states and expiring inactive streams. */
@SysUISingleton
-class MediaTimeoutListener @Inject constructor(
+class MediaTimeoutListener
+@Inject
+constructor(
private val mediaControllerFactory: MediaControllerFactory,
@Main private val mainExecutor: DelayableExecutor,
private val logger: MediaTimeoutLogger,
@@ -58,7 +58,9 @@ class MediaTimeoutListener @Inject constructor(
* Callback representing that a media object is now expired:
* @param key Media control unique identifier
* @param timedOut True when expired for {@code PAUSED_MEDIA_TIMEOUT} for active media,
+ * ```
* or {@code RESUME_MEDIA_TIMEOUT} for resume media
+ * ```
*/
lateinit var timeoutCallback: (String, Boolean) -> Unit
@@ -70,21 +72,25 @@ class MediaTimeoutListener @Inject constructor(
lateinit var stateCallback: (String, PlaybackState) -> Unit
init {
- statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
- override fun onDozingChanged(isDozing: Boolean) {
- if (!isDozing) {
- // Check whether any timeouts should have expired
- mediaListeners.forEach { (key, listener) ->
- if (listener.cancellation != null &&
- listener.expiration <= systemClock.elapsedRealtime()) {
- // We dozed too long - timeout now, and cancel the pending one
- listener.expireMediaTimeout(key, "timeout happened while dozing")
- listener.doTimeout()
+ statusBarStateController.addCallback(
+ object : StatusBarStateController.StateListener {
+ override fun onDozingChanged(isDozing: Boolean) {
+ if (!isDozing) {
+ // Check whether any timeouts should have expired
+ mediaListeners.forEach { (key, listener) ->
+ if (
+ listener.cancellation != null &&
+ listener.expiration <= systemClock.elapsedRealtime()
+ ) {
+ // We dozed too long - timeout now, and cancel the pending one
+ listener.expireMediaTimeout(key, "timeout happened while dozing")
+ listener.doTimeout()
+ }
}
}
}
}
- })
+ )
}
override fun onMediaDataLoaded(
@@ -147,10 +153,8 @@ class MediaTimeoutListener @Inject constructor(
return mediaListeners[key]?.timedOut ?: false
}
- private inner class PlaybackStateListener(
- var key: String,
- data: MediaData
- ) : MediaController.Callback() {
+ private inner class PlaybackStateListener(var key: String, data: MediaData) :
+ MediaController.Callback() {
var timedOut = false
var lastState: PlaybackState? = null
@@ -164,11 +168,12 @@ class MediaTimeoutListener @Inject constructor(
mediaController?.unregisterCallback(this)
field = value
val token = field.token
- mediaController = if (token != null) {
- mediaControllerFactory.create(token)
- } else {
- null
- }
+ mediaController =
+ if (token != null) {
+ mediaControllerFactory.create(token)
+ } else {
+ null
+ }
mediaController?.registerCallback(this)
// Let's register the cancellations, but not dispatch events now.
// Timeouts didn't happen yet and reentrant events are troublesome.
@@ -214,7 +219,8 @@ class MediaTimeoutListener @Inject constructor(
logger.logPlaybackState(key, state)
val playingStateSame = (state?.state?.isPlaying() == isPlaying())
- val actionsSame = (lastState?.actions == state?.actions) &&
+ val actionsSame =
+ (lastState?.actions == state?.actions) &&
areCustomActionListsEqual(lastState?.customActions, state?.customActions)
val resumptionChanged = resumption != mediaData.resumption
@@ -239,15 +245,14 @@ class MediaTimeoutListener @Inject constructor(
return
}
expireMediaTimeout(key, "PLAYBACK STATE CHANGED - $state, $resumption")
- val timeout = if (mediaData.resumption) {
- RESUME_MEDIA_TIMEOUT
- } else {
- PAUSED_MEDIA_TIMEOUT
- }
+ val timeout =
+ if (mediaData.resumption) {
+ RESUME_MEDIA_TIMEOUT
+ } else {
+ PAUSED_MEDIA_TIMEOUT
+ }
expiration = systemClock.elapsedRealtime() + timeout
- cancellation = mainExecutor.executeDelayed({
- doTimeout()
- }, timeout)
+ cancellation = mainExecutor.executeDelayed({ doTimeout() }, timeout)
} else {
expireMediaTimeout(key, "playback started - $state, $key")
timedOut = false
@@ -303,9 +308,11 @@ class MediaTimeoutListener @Inject constructor(
firstAction: PlaybackState.CustomAction,
secondAction: PlaybackState.CustomAction
): Boolean {
- if (firstAction.action != secondAction.action ||
+ if (
+ firstAction.action != secondAction.action ||
firstAction.name != secondAction.name ||
- firstAction.icon != secondAction.icon) {
+ firstAction.icon != secondAction.icon
+ ) {
return false
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
index 3abeef3ae124..8f3f0548230f 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaTimeoutLogger.kt
@@ -22,140 +22,91 @@ import com.android.systemui.log.dagger.MediaTimeoutListenerLog
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel
import javax.inject.Inject
+
private const val TAG = "MediaTimeout"
-/**
- * A buffered log for [MediaTimeoutListener] events
- */
+/** A buffered log for [MediaTimeoutListener] events */
@SysUISingleton
-class MediaTimeoutLogger @Inject constructor(
- @MediaTimeoutListenerLog private val buffer: LogBuffer
-) {
- fun logReuseListener(key: String) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = key
- },
- {
- "reuse listener: $str1"
- }
- )
-
- fun logMigrateListener(oldKey: String?, newKey: String?, hadListener: Boolean) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = oldKey
- str2 = newKey
- bool1 = hadListener
- },
- {
- "migrate from $str1 to $str2, had listener? $bool1"
- }
- )
+class MediaTimeoutLogger
+@Inject
+constructor(@MediaTimeoutListenerLog private val buffer: LogBuffer) {
+ fun logReuseListener(key: String) =
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = key }, { "reuse listener: $str1" })
- fun logUpdateListener(key: String, wasPlaying: Boolean) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = key
- bool1 = wasPlaying
- },
- {
- "updating $str1, was playing? $bool1"
- }
- )
+ fun logMigrateListener(oldKey: String?, newKey: String?, hadListener: Boolean) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = oldKey
+ str2 = newKey
+ bool1 = hadListener
+ },
+ { "migrate from $str1 to $str2, had listener? $bool1" }
+ )
- fun logDelayedUpdate(key: String) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = key
- },
- {
- "deliver delayed playback state for $str1"
- }
- )
+ fun logUpdateListener(key: String, wasPlaying: Boolean) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = key
+ bool1 = wasPlaying
+ },
+ { "updating $str1, was playing? $bool1" }
+ )
- fun logSessionDestroyed(key: String) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = key
- },
- {
- "session destroyed $str1"
- }
- )
+ fun logDelayedUpdate(key: String) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = key },
+ { "deliver delayed playback state for $str1" }
+ )
- fun logPlaybackState(key: String, state: PlaybackState?) = buffer.log(
- TAG,
- LogLevel.VERBOSE,
- {
- str1 = key
- str2 = state?.toString()
- },
- {
- "state update: key=$str1 state=$str2"
- }
- )
+ fun logSessionDestroyed(key: String) =
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = key }, { "session destroyed $str1" })
- fun logStateCallback(key: String) = buffer.log(
+ fun logPlaybackState(key: String, state: PlaybackState?) =
+ buffer.log(
TAG,
LogLevel.VERBOSE,
{
str1 = key
+ str2 = state?.toString()
},
- {
- "dispatching state update for $key"
- }
- )
+ { "state update: key=$str1 state=$str2" }
+ )
+
+ fun logStateCallback(key: String) =
+ buffer.log(TAG, LogLevel.VERBOSE, { str1 = key }, { "dispatching state update for $key" })
- fun logScheduleTimeout(key: String, playing: Boolean, resumption: Boolean) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = key
- bool1 = playing
- bool2 = resumption
- },
- {
- "schedule timeout $str1, playing=$bool1 resumption=$bool2"
- }
- )
+ fun logScheduleTimeout(key: String, playing: Boolean, resumption: Boolean) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = key
+ bool1 = playing
+ bool2 = resumption
+ },
+ { "schedule timeout $str1, playing=$bool1 resumption=$bool2" }
+ )
- fun logCancelIgnored(key: String) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = key
- },
- {
- "cancellation already exists for $str1"
- }
- )
+ fun logCancelIgnored(key: String) =
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = key }, { "cancellation already exists for $str1" })
- fun logTimeout(key: String) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = key
- },
- {
- "execute timeout for $str1"
- }
- )
+ fun logTimeout(key: String) =
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = key }, { "execute timeout for $str1" })
- fun logTimeoutCancelled(key: String, reason: String) = buffer.log(
- TAG,
- LogLevel.VERBOSE,
- {
- str1 = key
- str2 = reason
- },
- {
- "media timeout cancelled for $str1, reason: $str2"
- }
- )
-} \ No newline at end of file
+ fun logTimeoutCancelled(key: String, reason: String) =
+ buffer.log(
+ TAG,
+ LogLevel.VERBOSE,
+ {
+ str1 = key
+ str2 = reason
+ },
+ { "media timeout cancelled for $str1, reason: $str2" }
+ )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
index e5e10c2ca59a..4891297dbcf9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
@@ -50,7 +50,9 @@ private const val MEDIA_PREFERENCES = "media_control_prefs"
private const val MEDIA_PREFERENCE_KEY = "browser_components_"
@SysUISingleton
-class MediaResumeListener @Inject constructor(
+class MediaResumeListener
+@Inject
+constructor(
private val context: Context,
private val broadcastDispatcher: BroadcastDispatcher,
@Background private val backgroundExecutor: Executor,
@@ -62,7 +64,7 @@ class MediaResumeListener @Inject constructor(
private var useMediaResumption: Boolean = Utils.useMediaResumption(context)
private val resumeComponents: ConcurrentLinkedQueue<Pair<ComponentName, Long>> =
- ConcurrentLinkedQueue()
+ ConcurrentLinkedQueue()
private lateinit var mediaDataManager: MediaDataManager
@@ -75,40 +77,49 @@ class MediaResumeListener @Inject constructor(
private var currentUserId: Int = context.userId
@VisibleForTesting
- val userChangeReceiver = object : BroadcastReceiver() {
- override fun onReceive(context: Context, intent: Intent) {
- if (Intent.ACTION_USER_UNLOCKED == intent.action) {
- loadMediaResumptionControls()
- } else if (Intent.ACTION_USER_SWITCHED == intent.action) {
- currentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)
- loadSavedComponents()
+ val userChangeReceiver =
+ object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (Intent.ACTION_USER_UNLOCKED == intent.action) {
+ loadMediaResumptionControls()
+ } else if (Intent.ACTION_USER_SWITCHED == intent.action) {
+ currentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)
+ loadSavedComponents()
+ }
}
}
- }
- private val mediaBrowserCallback = object : ResumeMediaBrowser.Callback() {
- override fun addTrack(
- desc: MediaDescription,
- component: ComponentName,
- browser: ResumeMediaBrowser
- ) {
- val token = browser.token
- val appIntent = browser.appIntent
- val pm = context.getPackageManager()
- var appName: CharSequence = component.packageName
- val resumeAction = getResumeAction(component)
- try {
- appName = pm.getApplicationLabel(
- pm.getApplicationInfo(component.packageName, 0))
- } catch (e: PackageManager.NameNotFoundException) {
- Log.e(TAG, "Error getting package information", e)
- }
+ private val mediaBrowserCallback =
+ object : ResumeMediaBrowser.Callback() {
+ override fun addTrack(
+ desc: MediaDescription,
+ component: ComponentName,
+ browser: ResumeMediaBrowser
+ ) {
+ val token = browser.token
+ val appIntent = browser.appIntent
+ val pm = context.getPackageManager()
+ var appName: CharSequence = component.packageName
+ val resumeAction = getResumeAction(component)
+ try {
+ appName =
+ pm.getApplicationLabel(pm.getApplicationInfo(component.packageName, 0))
+ } catch (e: PackageManager.NameNotFoundException) {
+ Log.e(TAG, "Error getting package information", e)
+ }
- Log.d(TAG, "Adding resume controls $desc")
- mediaDataManager.addResumptionControls(currentUserId, desc, resumeAction, token,
- appName.toString(), appIntent, component.packageName)
+ Log.d(TAG, "Adding resume controls $desc")
+ mediaDataManager.addResumptionControls(
+ currentUserId,
+ desc,
+ resumeAction,
+ token,
+ appName.toString(),
+ appIntent,
+ component.packageName
+ )
+ }
}
- }
init {
if (useMediaResumption) {
@@ -116,8 +127,12 @@ class MediaResumeListener @Inject constructor(
val unlockFilter = IntentFilter()
unlockFilter.addAction(Intent.ACTION_USER_UNLOCKED)
unlockFilter.addAction(Intent.ACTION_USER_SWITCHED)
- broadcastDispatcher.registerReceiver(userChangeReceiver, unlockFilter, null,
- UserHandle.ALL)
+ broadcastDispatcher.registerReceiver(
+ userChangeReceiver,
+ unlockFilter,
+ null,
+ UserHandle.ALL
+ )
loadSavedComponents()
}
}
@@ -126,12 +141,15 @@ class MediaResumeListener @Inject constructor(
mediaDataManager = manager
// Add listener for resumption setting changes
- tunerService.addTunable(object : TunerService.Tunable {
- override fun onTuningChanged(key: String?, newValue: String?) {
- useMediaResumption = Utils.useMediaResumption(context)
- mediaDataManager.setMediaResumptionEnabled(useMediaResumption)
- }
- }, Settings.Secure.MEDIA_CONTROLS_RESUME)
+ tunerService.addTunable(
+ object : TunerService.Tunable {
+ override fun onTuningChanged(key: String?, newValue: String?) {
+ useMediaResumption = Utils.useMediaResumption(context)
+ mediaDataManager.setMediaResumptionEnabled(useMediaResumption)
+ }
+ },
+ Settings.Secure.MEDIA_CONTROLS_RESUME
+ )
}
private fun loadSavedComponents() {
@@ -139,8 +157,10 @@ class MediaResumeListener @Inject constructor(
resumeComponents.clear()
val prefs = context.getSharedPreferences(MEDIA_PREFERENCES, Context.MODE_PRIVATE)
val listString = prefs.getString(MEDIA_PREFERENCE_KEY + currentUserId, null)
- val components = listString?.split(ResumeMediaBrowser.DELIMITER.toRegex())
- ?.dropLastWhile { it.isEmpty() }
+ val components =
+ listString?.split(ResumeMediaBrowser.DELIMITER.toRegex())?.dropLastWhile {
+ it.isEmpty()
+ }
var needsUpdate = false
components?.forEach {
val info = it.split("/")
@@ -148,17 +168,18 @@ class MediaResumeListener @Inject constructor(
val className = info[1]
val component = ComponentName(packageName, className)
- val lastPlayed = if (info.size == 3) {
- try {
- info[2].toLong()
- } catch (e: NumberFormatException) {
+ val lastPlayed =
+ if (info.size == 3) {
+ try {
+ info[2].toLong()
+ } catch (e: NumberFormatException) {
+ needsUpdate = true
+ systemClock.currentTimeMillis()
+ }
+ } else {
needsUpdate = true
systemClock.currentTimeMillis()
}
- } else {
- needsUpdate = true
- systemClock.currentTimeMillis()
- }
resumeComponents.add(component to lastPlayed)
}
Log.d(TAG, "loaded resume components ${resumeComponents.toArray().contentToString()}")
@@ -169,9 +190,7 @@ class MediaResumeListener @Inject constructor(
}
}
- /**
- * Load controls for resuming media, if available
- */
+ /** Load controls for resuming media, if available */
private fun loadMediaResumptionControls() {
if (!useMediaResumption) {
return
@@ -207,9 +226,7 @@ class MediaResumeListener @Inject constructor(
val serviceIntent = Intent(MediaBrowserService.SERVICE_INTERFACE)
val resumeInfo = pm.queryIntentServices(serviceIntent, 0)
- val inf = resumeInfo?.filter {
- it.serviceInfo.packageName == data.packageName
- }
+ val inf = resumeInfo?.filter { it.serviceInfo.packageName == data.packageName }
if (inf != null && inf.size > 0) {
backgroundExecutor.execute {
tryUpdateResumptionList(key, inf!!.get(0).componentInfo.componentName)
@@ -230,7 +247,8 @@ class MediaResumeListener @Inject constructor(
Log.d(TAG, "Testing if we can connect to $componentName")
// Set null action to prevent additional attempts to connect
mediaDataManager.setResumeAction(key, null)
- mediaBrowser = mediaBrowserFactory.create(
+ mediaBrowser =
+ mediaBrowserFactory.create(
object : ResumeMediaBrowser.Callback() {
override fun onConnected() {
Log.d(TAG, "Connected to $componentName")
@@ -253,7 +271,8 @@ class MediaResumeListener @Inject constructor(
mediaBrowser = null
}
},
- componentName)
+ componentName
+ )
mediaBrowser?.testConnection()
}
@@ -288,9 +307,7 @@ class MediaResumeListener @Inject constructor(
prefs.edit().putString(MEDIA_PREFERENCE_KEY + currentUserId, sb.toString()).apply()
}
- /**
- * Get a runnable which will resume media playback
- */
+ /** Get a runnable which will resume media playback */
private fun getResumeAction(componentName: ComponentName): Runnable {
return Runnable {
mediaBrowser = mediaBrowserFactory.create(null, componentName)
@@ -299,8 +316,6 @@ class MediaResumeListener @Inject constructor(
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
- pw.apply {
- println("resumeComponents: $resumeComponents")
- }
+ pw.apply { println("resumeComponents: $resumeComponents") }
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
index b633de9d836a..335ce1d3d694 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserLogger.kt
@@ -25,50 +25,49 @@ import javax.inject.Inject
/** A logger for events in [ResumeMediaBrowser]. */
@SysUISingleton
-class ResumeMediaBrowserLogger @Inject constructor(
- @MediaBrowserLog private val buffer: LogBuffer
-) {
+class ResumeMediaBrowserLogger @Inject constructor(@MediaBrowserLog private val buffer: LogBuffer) {
/** Logs that we've initiated a connection to a [android.media.browse.MediaBrowser]. */
- fun logConnection(componentName: ComponentName, reason: String) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = componentName.toShortString()
- str2 = reason
- },
- { "Connecting browser for component $str1 due to $str2" }
- )
+ fun logConnection(componentName: ComponentName, reason: String) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = componentName.toShortString()
+ str2 = reason
+ },
+ { "Connecting browser for component $str1 due to $str2" }
+ )
/** Logs that we've disconnected from a [android.media.browse.MediaBrowser]. */
- fun logDisconnect(componentName: ComponentName) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = componentName.toShortString()
- },
- { "Disconnecting browser for component $str1" }
- )
+ fun logDisconnect(componentName: ComponentName) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = componentName.toShortString() },
+ { "Disconnecting browser for component $str1" }
+ )
/**
* Logs that we received a [android.media.session.MediaController.Callback.onSessionDestroyed]
* event.
*
* @param isBrowserConnected true if there's a currently connected
+ * ```
* [android.media.browse.MediaBrowser] and false otherwise.
- * @param componentName the component name for the [ResumeMediaBrowser] that triggered this log.
+ * @param componentName
+ * ```
+ * the component name for the [ResumeMediaBrowser] that triggered this log.
*/
- fun logSessionDestroyed(
- isBrowserConnected: Boolean,
- componentName: ComponentName
- ) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- bool1 = isBrowserConnected
- str1 = componentName.toShortString()
- },
- { "Session destroyed. Active browser = $bool1. Browser component = $str1." }
- )
+ fun logSessionDestroyed(isBrowserConnected: Boolean, componentName: ComponentName) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ bool1 = isBrowserConnected
+ str1 = componentName.toShortString()
+ },
+ { "Session destroyed. Active browser = $bool1. Browser component = $str1." }
+ )
}
private const val TAG = "MediaBrowser"
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt
index a64d08fe9f01..d2793bca867b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/AnimationBindHandler.kt
@@ -20,13 +20,17 @@ import android.graphics.drawable.Animatable2
import android.graphics.drawable.Drawable
/**
- * AnimationBindHandler is responsible for tracking the bound animation state and preventing
- * jank and conflicts due to media notifications arriving at any time during an animation. It
- * does this in two parts.
- * - Exit animations fired as a result of user input are tracked. When these are running, any
+ * AnimationBindHandler is responsible for tracking the bound animation state and preventing jank
+ * and conflicts due to media notifications arriving at any time during an animation. It does this
+ * in two parts.
+ * - Exit animations fired as a result of user input are tracked. When these are running, any
+ * ```
* bind actions are delayed until the animation completes (and then fired in sequence).
- * - Continuous animations are tracked using their rebind id. Later calls using the same
+ * ```
+ * - Continuous animations are tracked using their rebind id. Later calls using the same
+ * ```
* rebind id will be totally ignored to prevent the continuous animation from restarting.
+ * ```
*/
internal class AnimationBindHandler : Animatable2.AnimationCallback() {
private val onAnimationsComplete = mutableListOf<() -> Unit>()
@@ -37,10 +41,10 @@ internal class AnimationBindHandler : Animatable2.AnimationCallback() {
get() = registrations.any { it.isRunning }
/**
- * This check prevents rebinding to the action button if the identifier has not changed. A
- * null value is always considered to be changed. This is used to prevent the connecting
- * animation from rebinding (and restarting) if multiple buffer PlaybackStates are pushed by
- * an application in a row.
+ * This check prevents rebinding to the action button if the identifier has not changed. A null
+ * value is always considered to be changed. This is used to prevent the connecting animation
+ * from rebinding (and restarting) if multiple buffer PlaybackStates are pushed by an
+ * application in a row.
*/
fun updateRebindId(newRebindId: Int?): Boolean {
if (rebindId == null || newRebindId == null || rebindId != newRebindId) {
@@ -78,4 +82,4 @@ internal class AnimationBindHandler : Animatable2.AnimationCallback() {
onAnimationsComplete.clear()
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
index dda465a7a695..61ef2f1838e7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/ColorSchemeTransition.kt
@@ -39,12 +39,11 @@ interface ColorTransition {
}
/**
- * A [ColorTransition] that animates between two specific colors.
- * It uses a ValueAnimator to execute the animation and interpolate between the source color and
- * the target color.
+ * A [ColorTransition] that animates between two specific colors. It uses a ValueAnimator to execute
+ * the animation and interpolate between the source color and the target color.
*
- * Selection of the target color from the scheme, and application of the interpolated color
- * are delegated to callbacks.
+ * Selection of the target color from the scheme, and application of the interpolated color are
+ * delegated to callbacks.
*/
open class AnimatingColorTransition(
private val defaultColor: Int,
@@ -59,9 +58,8 @@ open class AnimatingColorTransition(
var targetColor: Int = defaultColor
override fun onAnimationUpdate(animation: ValueAnimator) {
- currentColor = argbEvaluator.evaluate(
- animation.animatedFraction, sourceColor, targetColor
- ) as Int
+ currentColor =
+ argbEvaluator.evaluate(animation.animatedFraction, sourceColor, targetColor) as Int
applyColor(currentColor)
}
@@ -91,111 +89,126 @@ open class AnimatingColorTransition(
}
typealias AnimatingColorTransitionFactory =
- (Int, (ColorScheme) -> Int, (Int) -> Unit) -> AnimatingColorTransition
+ (Int, (ColorScheme) -> Int, (Int) -> Unit) -> AnimatingColorTransition
/**
- * ColorSchemeTransition constructs a ColorTransition for each color in the scheme
- * that needs to be transitioned when changed. It also sets up the assignment functions for sending
- * the sending the interpolated colors to the appropriate views.
+ * ColorSchemeTransition constructs a ColorTransition for each color in the scheme that needs to be
+ * transitioned when changed. It also sets up the assignment functions for sending the sending the
+ * interpolated colors to the appropriate views.
*/
-class ColorSchemeTransition internal constructor(
+class ColorSchemeTransition
+internal constructor(
private val context: Context,
private val mediaViewHolder: MediaViewHolder,
animatingColorTransitionFactory: AnimatingColorTransitionFactory
) {
- constructor(context: Context, mediaViewHolder: MediaViewHolder) :
- this(context, mediaViewHolder, ::AnimatingColorTransition)
+ constructor(
+ context: Context,
+ mediaViewHolder: MediaViewHolder
+ ) : this(context, mediaViewHolder, ::AnimatingColorTransition)
val bgColor = context.getColor(com.android.systemui.R.color.material_dynamic_secondary95)
- val surfaceColor = animatingColorTransitionFactory(
- bgColor,
- ::surfaceFromScheme
- ) { surfaceColor ->
- val colorList = ColorStateList.valueOf(surfaceColor)
- mediaViewHolder.seamlessIcon.imageTintList = colorList
- mediaViewHolder.seamlessText.setTextColor(surfaceColor)
- mediaViewHolder.albumView.backgroundTintList = colorList
- mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor)
- }
-
- val accentPrimary = animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorPrimary),
- ::accentPrimaryFromScheme
- ) { accentPrimary ->
- val accentColorList = ColorStateList.valueOf(accentPrimary)
- mediaViewHolder.actionPlayPause.backgroundTintList = accentColorList
- mediaViewHolder.gutsViewHolder.setAccentPrimaryColor(accentPrimary)
- }
+ val surfaceColor =
+ animatingColorTransitionFactory(bgColor, ::surfaceFromScheme) { surfaceColor ->
+ val colorList = ColorStateList.valueOf(surfaceColor)
+ mediaViewHolder.seamlessIcon.imageTintList = colorList
+ mediaViewHolder.seamlessText.setTextColor(surfaceColor)
+ mediaViewHolder.albumView.backgroundTintList = colorList
+ mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor)
+ }
- val accentSecondary = animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorPrimary),
- ::accentSecondaryFromScheme
- ) { accentSecondary ->
- val colorList = ColorStateList.valueOf(accentSecondary)
- (mediaViewHolder.seamlessButton.background as? RippleDrawable)?.let {
- it.setColor(colorList)
- it.effectColor = colorList
+ val accentPrimary =
+ animatingColorTransitionFactory(
+ loadDefaultColor(R.attr.textColorPrimary),
+ ::accentPrimaryFromScheme
+ ) { accentPrimary ->
+ val accentColorList = ColorStateList.valueOf(accentPrimary)
+ mediaViewHolder.actionPlayPause.backgroundTintList = accentColorList
+ mediaViewHolder.gutsViewHolder.setAccentPrimaryColor(accentPrimary)
}
- }
- val colorSeamless = animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorPrimary),
- { colorScheme: ColorScheme ->
- // A1-100 dark in dark theme, A1-200 in light theme
- if (context.resources.configuration.uiMode and
- Configuration.UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES)
- colorScheme.accent1[2]
- else colorScheme.accent1[3]
- }, { seamlessColor: Int ->
- val accentColorList = ColorStateList.valueOf(seamlessColor)
- mediaViewHolder.seamlessButton.backgroundTintList = accentColorList
- })
-
- val textPrimary = animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorPrimary),
- ::textPrimaryFromScheme
- ) { textPrimary ->
- mediaViewHolder.titleText.setTextColor(textPrimary)
- val textColorList = ColorStateList.valueOf(textPrimary)
- mediaViewHolder.seekBar.thumb.setTintList(textColorList)
- mediaViewHolder.seekBar.progressTintList = textColorList
- mediaViewHolder.scrubbingElapsedTimeView.setTextColor(textColorList)
- mediaViewHolder.scrubbingTotalTimeView.setTextColor(textColorList)
- for (button in mediaViewHolder.getTransparentActionButtons()) {
- button.imageTintList = textColorList
+ val accentSecondary =
+ animatingColorTransitionFactory(
+ loadDefaultColor(R.attr.textColorPrimary),
+ ::accentSecondaryFromScheme
+ ) { accentSecondary ->
+ val colorList = ColorStateList.valueOf(accentSecondary)
+ (mediaViewHolder.seamlessButton.background as? RippleDrawable)?.let {
+ it.setColor(colorList)
+ it.effectColor = colorList
+ }
}
- mediaViewHolder.gutsViewHolder.setTextPrimaryColor(textPrimary)
- }
- val textPrimaryInverse = animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorPrimaryInverse),
- ::textPrimaryInverseFromScheme
- ) { textPrimaryInverse ->
- mediaViewHolder.actionPlayPause.imageTintList = ColorStateList.valueOf(textPrimaryInverse)
- }
+ val colorSeamless =
+ animatingColorTransitionFactory(
+ loadDefaultColor(R.attr.textColorPrimary),
+ { colorScheme: ColorScheme ->
+ // A1-100 dark in dark theme, A1-200 in light theme
+ if (
+ context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK ==
+ UI_MODE_NIGHT_YES
+ )
+ colorScheme.accent1[2]
+ else colorScheme.accent1[3]
+ },
+ { seamlessColor: Int ->
+ val accentColorList = ColorStateList.valueOf(seamlessColor)
+ mediaViewHolder.seamlessButton.backgroundTintList = accentColorList
+ }
+ )
+
+ val textPrimary =
+ animatingColorTransitionFactory(
+ loadDefaultColor(R.attr.textColorPrimary),
+ ::textPrimaryFromScheme
+ ) { textPrimary ->
+ mediaViewHolder.titleText.setTextColor(textPrimary)
+ val textColorList = ColorStateList.valueOf(textPrimary)
+ mediaViewHolder.seekBar.thumb.setTintList(textColorList)
+ mediaViewHolder.seekBar.progressTintList = textColorList
+ mediaViewHolder.scrubbingElapsedTimeView.setTextColor(textColorList)
+ mediaViewHolder.scrubbingTotalTimeView.setTextColor(textColorList)
+ for (button in mediaViewHolder.getTransparentActionButtons()) {
+ button.imageTintList = textColorList
+ }
+ mediaViewHolder.gutsViewHolder.setTextPrimaryColor(textPrimary)
+ }
- val textSecondary = animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorSecondary),
- ::textSecondaryFromScheme
- ) { textSecondary -> mediaViewHolder.artistText.setTextColor(textSecondary) }
+ val textPrimaryInverse =
+ animatingColorTransitionFactory(
+ loadDefaultColor(R.attr.textColorPrimaryInverse),
+ ::textPrimaryInverseFromScheme
+ ) { textPrimaryInverse ->
+ mediaViewHolder.actionPlayPause.imageTintList =
+ ColorStateList.valueOf(textPrimaryInverse)
+ }
- val textTertiary = animatingColorTransitionFactory(
- loadDefaultColor(R.attr.textColorTertiary),
- ::textTertiaryFromScheme
- ) { textTertiary ->
- mediaViewHolder.seekBar.progressBackgroundTintList = ColorStateList.valueOf(textTertiary)
- }
+ val textSecondary =
+ animatingColorTransitionFactory(
+ loadDefaultColor(R.attr.textColorSecondary),
+ ::textSecondaryFromScheme
+ ) { textSecondary -> mediaViewHolder.artistText.setTextColor(textSecondary) }
+
+ val textTertiary =
+ animatingColorTransitionFactory(
+ loadDefaultColor(R.attr.textColorTertiary),
+ ::textTertiaryFromScheme
+ ) { textTertiary ->
+ mediaViewHolder.seekBar.progressBackgroundTintList =
+ ColorStateList.valueOf(textTertiary)
+ }
- val colorTransitions = arrayOf(
- surfaceColor,
- colorSeamless,
- accentPrimary,
- accentSecondary,
- textPrimary,
- textPrimaryInverse,
- textSecondary,
- textTertiary,
- )
+ val colorTransitions =
+ arrayOf(
+ surfaceColor,
+ colorSeamless,
+ accentPrimary,
+ accentSecondary,
+ textPrimary,
+ textPrimaryInverse,
+ textSecondary,
+ textTertiary,
+ )
private fun loadDefaultColor(id: Int): Int {
return Utils.getColorAttr(context, id).defaultColor
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
index 2440c2481ed7..9f86cd88788b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/IlluminationDrawable.kt
@@ -42,22 +42,20 @@ import org.xmlpull.v1.XmlPullParser
private const val BACKGROUND_ANIM_DURATION = 370L
-/**
- * Drawable that can draw an animated gradient when tapped.
- */
+/** Drawable that can draw an animated gradient when tapped. */
@Keep
class IlluminationDrawable : Drawable() {
private var themeAttrs: IntArray? = null
private var cornerRadiusOverride = -1f
var cornerRadius = 0f
- get() {
- return if (cornerRadiusOverride >= 0) {
- cornerRadiusOverride
- } else {
- field
+ get() {
+ return if (cornerRadiusOverride >= 0) {
+ cornerRadiusOverride
+ } else {
+ field
+ }
}
- }
private var highlightColor = Color.TRANSPARENT
private var tmpHsl = floatArrayOf(0f, 0f, 0f)
private var paint = Paint()
@@ -65,22 +63,27 @@ class IlluminationDrawable : Drawable() {
private val lightSources = arrayListOf<LightSourceDrawable>()
private var backgroundColor = Color.TRANSPARENT
- set(value) {
- if (value == field) {
- return
+ set(value) {
+ if (value == field) {
+ return
+ }
+ field = value
+ animateBackground()
}
- field = value
- animateBackground()
- }
private var backgroundAnimation: ValueAnimator? = null
- /**
- * Draw background and gradient.
- */
+ /** Draw background and gradient. */
override fun draw(canvas: Canvas) {
- canvas.drawRoundRect(0f, 0f, bounds.width().toFloat(), bounds.height().toFloat(),
- cornerRadius, cornerRadius, paint)
+ canvas.drawRoundRect(
+ 0f,
+ 0f,
+ bounds.width().toFloat(),
+ bounds.height().toFloat(),
+ cornerRadius,
+ cornerRadius,
+ paint
+ )
}
override fun getOutline(outline: Outline) {
@@ -105,12 +108,11 @@ class IlluminationDrawable : Drawable() {
private fun updateStateFromTypedArray(a: TypedArray) {
if (a.hasValue(R.styleable.IlluminationDrawable_cornerRadius)) {
- cornerRadius = a.getDimension(R.styleable.IlluminationDrawable_cornerRadius,
- cornerRadius)
+ cornerRadius =
+ a.getDimension(R.styleable.IlluminationDrawable_cornerRadius, cornerRadius)
}
if (a.hasValue(R.styleable.IlluminationDrawable_highlight)) {
- highlight = a.getInteger(R.styleable.IlluminationDrawable_highlight, 0) /
- 100f
+ highlight = a.getInteger(R.styleable.IlluminationDrawable_highlight, 0) / 100f
}
}
@@ -163,34 +165,42 @@ class IlluminationDrawable : Drawable() {
private fun animateBackground() {
ColorUtils.colorToHSL(backgroundColor, tmpHsl)
val L = tmpHsl[2]
- tmpHsl[2] = MathUtils.constrain(if (L < 1f - highlight) {
- L + highlight
- } else {
- L - highlight
- }, 0f, 1f)
+ tmpHsl[2] =
+ MathUtils.constrain(
+ if (L < 1f - highlight) {
+ L + highlight
+ } else {
+ L - highlight
+ },
+ 0f,
+ 1f
+ )
val initialBackground = paint.color
val initialHighlight = highlightColor
val finalHighlight = ColorUtils.HSLToColor(tmpHsl)
backgroundAnimation?.cancel()
- backgroundAnimation = ValueAnimator.ofFloat(0f, 1f).apply {
- duration = BACKGROUND_ANIM_DURATION
- interpolator = Interpolators.FAST_OUT_LINEAR_IN
- addUpdateListener {
- val progress = it.animatedValue as Float
- paint.color = blendARGB(initialBackground, backgroundColor, progress)
- highlightColor = blendARGB(initialHighlight, finalHighlight, progress)
- lightSources.forEach { it.highlightColor = highlightColor }
- invalidateSelf()
- }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- backgroundAnimation = null
+ backgroundAnimation =
+ ValueAnimator.ofFloat(0f, 1f).apply {
+ duration = BACKGROUND_ANIM_DURATION
+ interpolator = Interpolators.FAST_OUT_LINEAR_IN
+ addUpdateListener {
+ val progress = it.animatedValue as Float
+ paint.color = blendARGB(initialBackground, backgroundColor, progress)
+ highlightColor = blendARGB(initialHighlight, finalHighlight, progress)
+ lightSources.forEach { it.highlightColor = highlightColor }
+ invalidateSelf()
}
- })
- start()
- }
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ backgroundAnimation = null
+ }
+ }
+ )
+ start()
+ }
}
override fun setTintList(tint: ColorStateList?) {
@@ -215,4 +225,4 @@ class IlluminationDrawable : Drawable() {
fun setCornerRadiusOverride(cornerRadius: Float?) {
cornerRadiusOverride = cornerRadius ?: -1f
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
index c9aa999a0a2d..899148b0014c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
@@ -45,7 +45,9 @@ import javax.inject.Named
* switches media player positioning between split pane container vs single pane container
*/
@SysUISingleton
-class KeyguardMediaController @Inject constructor(
+class KeyguardMediaController
+@Inject
+constructor(
@param:Named(KEYGUARD) private val mediaHost: MediaHost,
private val bypassController: KeyguardBypassController,
private val statusBarStateController: SysuiStatusBarStateController,
@@ -56,34 +58,40 @@ class KeyguardMediaController @Inject constructor(
) {
init {
- statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
- override fun onStateChanged(newState: Int) {
- refreshMediaPosition()
+ statusBarStateController.addCallback(
+ object : StatusBarStateController.StateListener {
+ override fun onStateChanged(newState: Int) {
+ refreshMediaPosition()
+ }
}
- })
- configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
- override fun onConfigChanged(newConfig: Configuration?) {
- updateResources()
+ )
+ configurationController.addCallback(
+ object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ updateResources()
+ }
}
- })
+ )
- val settingsObserver: ContentObserver = object : ContentObserver(handler) {
- override fun onChange(selfChange: Boolean, uri: Uri?) {
- if (uri == lockScreenMediaPlayerUri) {
- allowMediaPlayerOnLockScreen =
+ val settingsObserver: ContentObserver =
+ object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ if (uri == lockScreenMediaPlayerUri) {
+ allowMediaPlayerOnLockScreen =
secureSettings.getBoolForUser(
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
- true,
- UserHandle.USER_CURRENT
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ true,
+ UserHandle.USER_CURRENT
)
- refreshMediaPosition()
+ refreshMediaPosition()
+ }
}
}
- }
secureSettings.registerContentObserverForUser(
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
- settingsObserver,
- UserHandle.USER_ALL)
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ settingsObserver,
+ UserHandle.USER_ALL
+ )
// First let's set the desired state that we want for this host
mediaHost.expansion = MediaHostState.EXPANDED
@@ -110,27 +118,21 @@ class KeyguardMediaController @Inject constructor(
refreshMediaPosition()
}
- /**
- * Is the media player visible?
- */
+ /** Is the media player visible? */
var visible = false
private set
var visibilityChangedListener: ((Boolean) -> Unit)? = null
- /**
- * single pane media container placed at the top of the notifications list
- */
+ /** single pane media container placed at the top of the notifications list */
var singlePaneContainer: MediaContainerView? = null
private set
private var splitShadeContainer: ViewGroup? = null
- /**
- * Track the media player setting status on lock screen.
- */
+ /** Track the media player setting status on lock screen. */
private var allowMediaPlayerOnLockScreen: Boolean = true
private val lockScreenMediaPlayerUri =
- secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
+ secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
/**
* Attaches media container in single pane mode, situated at the top of the notifications list
@@ -146,9 +148,7 @@ class KeyguardMediaController @Inject constructor(
onMediaHostVisibilityChanged(mediaHost.visible)
}
- /**
- * Called whenever the media hosts visibility changes
- */
+ /** Called whenever the media hosts visibility changes */
private fun onMediaHostVisibilityChanged(visible: Boolean) {
refreshMediaPosition()
if (visible) {
@@ -159,9 +159,7 @@ class KeyguardMediaController @Inject constructor(
}
}
- /**
- * Attaches media container in split shade mode, situated to the left of notifications
- */
+ /** Attaches media container in split shade mode, situated to the left of notifications */
fun attachSplitShadeContainer(container: ViewGroup) {
splitShadeContainer = container
reattachHostView()
@@ -183,9 +181,7 @@ class KeyguardMediaController @Inject constructor(
}
if (activeContainer?.childCount == 0) {
// Detach the hostView from its parent view if exists
- mediaHost.hostView.parent?.let {
- (it as? ViewGroup)?.removeView(mediaHost.hostView)
- }
+ mediaHost.hostView.parent?.let { (it as? ViewGroup)?.removeView(mediaHost.hostView) }
activeContainer.addView(mediaHost.hostView)
}
}
@@ -193,7 +189,8 @@ class KeyguardMediaController @Inject constructor(
fun refreshMediaPosition() {
val keyguardOrUserSwitcher = (statusBarStateController.state == StatusBarState.KEYGUARD)
// mediaHost.visible required for proper animations handling
- visible = mediaHost.visible &&
+ visible =
+ mediaHost.visible &&
!bypassController.bypassEnabled &&
keyguardOrUserSwitcher &&
allowMediaPlayerOnLockScreen
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
index 0d2efdf37b25..dd5c2bf497cb 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/LightSourceDrawable.kt
@@ -55,9 +55,7 @@ private data class RippleData(
var highlight: Float
)
-/**
- * Drawable that can draw an animated gradient when tapped.
- */
+/** Drawable that can draw an animated gradient when tapped. */
@Keep
class LightSourceDrawable : Drawable() {
@@ -67,17 +65,15 @@ class LightSourceDrawable : Drawable() {
private var paint = Paint()
var highlightColor = Color.WHITE
- set(value) {
- if (field == value) {
- return
+ set(value) {
+ if (field == value) {
+ return
+ }
+ field = value
+ invalidateSelf()
}
- field = value
- invalidateSelf()
- }
- /**
- * Draw a small highlight under the finger before expanding (or cancelling) it.
- */
+ /** Draw a small highlight under the finger before expanding (or cancelling) it. */
private var active: Boolean = false
set(value) {
if (value == field) {
@@ -91,46 +87,54 @@ class LightSourceDrawable : Drawable() {
rippleData.progress = RIPPLE_DOWN_PROGRESS
} else {
rippleAnimation?.cancel()
- rippleAnimation = ValueAnimator.ofFloat(rippleData.alpha, 0f).apply {
- duration = RIPPLE_CANCEL_DURATION
- interpolator = Interpolators.LINEAR_OUT_SLOW_IN
- addUpdateListener {
- rippleData.alpha = it.animatedValue as Float
- invalidateSelf()
- }
- addListener(object : AnimatorListenerAdapter() {
- var cancelled = false
- override fun onAnimationCancel(animation: Animator?) {
- cancelled = true
- }
-
- override fun onAnimationEnd(animation: Animator?) {
- if (cancelled) {
- return
- }
- rippleData.progress = 0f
- rippleData.alpha = 0f
- rippleAnimation = null
+ rippleAnimation =
+ ValueAnimator.ofFloat(rippleData.alpha, 0f).apply {
+ duration = RIPPLE_CANCEL_DURATION
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ addUpdateListener {
+ rippleData.alpha = it.animatedValue as Float
invalidateSelf()
}
- })
- start()
- }
+ addListener(
+ object : AnimatorListenerAdapter() {
+ var cancelled = false
+ override fun onAnimationCancel(animation: Animator?) {
+ cancelled = true
+ }
+
+ override fun onAnimationEnd(animation: Animator?) {
+ if (cancelled) {
+ return
+ }
+ rippleData.progress = 0f
+ rippleData.alpha = 0f
+ rippleAnimation = null
+ invalidateSelf()
+ }
+ }
+ )
+ start()
+ }
}
invalidateSelf()
}
private var rippleAnimation: Animator? = null
- /**
- * Draw background and gradient.
- */
+ /** Draw background and gradient. */
override fun draw(canvas: Canvas) {
val radius = lerp(rippleData.minSize, rippleData.maxSize, rippleData.progress)
val centerColor =
- ColorUtils.setAlphaComponent(highlightColor, (rippleData.alpha * 255).toInt())
- paint.shader = RadialGradient(rippleData.x, rippleData.y, radius,
- intArrayOf(centerColor, Color.TRANSPARENT), GRADIENT_STOPS, Shader.TileMode.CLAMP)
+ ColorUtils.setAlphaComponent(highlightColor, (rippleData.alpha * 255).toInt())
+ paint.shader =
+ RadialGradient(
+ rippleData.x,
+ rippleData.y,
+ radius,
+ intArrayOf(centerColor, Color.TRANSPARENT),
+ GRADIENT_STOPS,
+ Shader.TileMode.CLAMP
+ )
canvas.drawCircle(rippleData.x, rippleData.y, radius, paint)
}
@@ -162,8 +166,8 @@ class LightSourceDrawable : Drawable() {
rippleData.maxSize = a.getDimension(R.styleable.IlluminationDrawable_rippleMaxSize, 0f)
}
if (a.hasValue(R.styleable.IlluminationDrawable_highlight)) {
- rippleData.highlight = a.getInteger(R.styleable.IlluminationDrawable_highlight, 0) /
- 100f
+ rippleData.highlight =
+ a.getInteger(R.styleable.IlluminationDrawable_highlight, 0) / 100f
}
}
@@ -193,40 +197,44 @@ class LightSourceDrawable : Drawable() {
invalidateSelf()
}
- /**
- * Draws an animated ripple that expands fading away.
- */
+ /** Draws an animated ripple that expands fading away. */
private fun illuminate() {
rippleData.alpha = 1f
invalidateSelf()
rippleAnimation?.cancel()
- rippleAnimation = AnimatorSet().apply {
- playTogether(ValueAnimator.ofFloat(1f, 0f).apply {
- startDelay = 133
- duration = RIPPLE_ANIM_DURATION - startDelay
- interpolator = Interpolators.LINEAR_OUT_SLOW_IN
- addUpdateListener {
- rippleData.alpha = it.animatedValue as Float
- invalidateSelf()
- }
- }, ValueAnimator.ofFloat(rippleData.progress, 1f).apply {
- duration = RIPPLE_ANIM_DURATION
- interpolator = Interpolators.LINEAR_OUT_SLOW_IN
- addUpdateListener {
- rippleData.progress = it.animatedValue as Float
- invalidateSelf()
- }
- })
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- rippleData.progress = 0f
- rippleAnimation = null
- invalidateSelf()
- }
- })
- start()
- }
+ rippleAnimation =
+ AnimatorSet().apply {
+ playTogether(
+ ValueAnimator.ofFloat(1f, 0f).apply {
+ startDelay = 133
+ duration = RIPPLE_ANIM_DURATION - startDelay
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ addUpdateListener {
+ rippleData.alpha = it.animatedValue as Float
+ invalidateSelf()
+ }
+ },
+ ValueAnimator.ofFloat(rippleData.progress, 1f).apply {
+ duration = RIPPLE_ANIM_DURATION
+ interpolator = Interpolators.LINEAR_OUT_SLOW_IN
+ addUpdateListener {
+ rippleData.progress = it.animatedValue as Float
+ invalidateSelf()
+ }
+ }
+ )
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ rippleData.progress = 0f
+ rippleAnimation = null
+ invalidateSelf()
+ }
+ }
+ )
+ start()
+ }
}
override fun setHotspot(x: Float, y: Float) {
@@ -251,8 +259,13 @@ class LightSourceDrawable : Drawable() {
override fun getDirtyBounds(): Rect {
val radius = lerp(rippleData.minSize, rippleData.maxSize, rippleData.progress)
- val bounds = Rect((rippleData.x - radius).toInt(), (rippleData.y - radius).toInt(),
- (rippleData.x + radius).toInt(), (rippleData.y + radius).toInt())
+ val bounds =
+ Rect(
+ (rippleData.x - radius).toInt(),
+ (rippleData.y - radius).toInt(),
+ (rippleData.x + radius).toInt(),
+ (rippleData.y + radius).toInt()
+ )
bounds.union(super.getDirtyBounds())
return bounds
}
@@ -293,4 +306,4 @@ class LightSourceDrawable : Drawable() {
return changed
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index 96fe335c9ab3..e38c1baaeae9 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.media.controls.ui
import android.app.PendingIntent
@@ -52,11 +68,13 @@ private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS)
private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
/**
- * Class that is responsible for keeping the view carousel up to date.
- * This also handles changes in state and applies them to the media carousel like the expansion.
+ * Class that is responsible for keeping the view carousel up to date. This also handles changes in
+ * state and applies them to the media carousel like the expansion.
*/
@SysUISingleton
-class MediaCarouselController @Inject constructor(
+class MediaCarouselController
+@Inject
+constructor(
private val context: Context,
private val mediaControlPanelFactory: Provider<MediaControlPanel>,
private val visualStabilityProvider: VisualStabilityProvider,
@@ -72,60 +90,42 @@ class MediaCarouselController @Inject constructor(
private val logger: MediaUiEventLogger,
private val debugLogger: MediaCarouselControllerLogger
) : Dumpable {
- /**
- * The current width of the carousel
- */
+ /** The current width of the carousel */
private var currentCarouselWidth: Int = 0
- /**
- * The current height of the carousel
- */
+ /** The current height of the carousel */
private var currentCarouselHeight: Int = 0
- /**
- * Are we currently showing only active players
- */
+ /** Are we currently showing only active players */
private var currentlyShowingOnlyActive: Boolean = false
- /**
- * Is the player currently visible (at the end of the transformation
- */
+ /** Is the player currently visible (at the end of the transformation */
private var playersVisible: Boolean = false
/**
* The desired location where we'll be at the end of the transformation. Usually this matches
* the end location, except when we're still waiting on a state update call.
*/
- @MediaLocation
- private var desiredLocation: Int = -1
+ @MediaLocation private var desiredLocation: Int = -1
/**
* The ending location of the view where it ends when all animations and transitions have
* finished
*/
- @MediaLocation
- @VisibleForTesting
- var currentEndLocation: Int = -1
+ @MediaLocation @VisibleForTesting var currentEndLocation: Int = -1
/**
* The ending location of the view where it ends when all animations and transitions have
* finished
*/
- @MediaLocation
- private var currentStartLocation: Int = -1
+ @MediaLocation private var currentStartLocation: Int = -1
- /**
- * The progress of the transition or 1.0 if there is no transition happening
- */
+ /** The progress of the transition or 1.0 if there is no transition happening */
private var currentTransitionProgress: Float = 1.0f
- /**
- * The measured width of the carousel
- */
+ /** The measured width of the carousel */
private var carouselMeasureWidth: Int = 0
- /**
- * The measured height of the carousel
- */
+ /** The measured height of the carousel */
private var carouselMeasureHeight: Int = 0
private var desiredHostState: MediaHostState? = null
private val mediaCarousel: MediaScrollView
@@ -135,8 +135,7 @@ class MediaCarouselController @Inject constructor(
lateinit var settingsButton: View
private set
private val mediaContent: ViewGroup
- @VisibleForTesting
- val pageIndicator: PageIndicator
+ @VisibleForTesting val pageIndicator: PageIndicator
private val visualStabilityCallback: OnReorderingAllowedListener
private var needsReordering: Boolean = false
private var keysNeedRemoval = mutableSetOf<String>()
@@ -146,7 +145,7 @@ class MediaCarouselController @Inject constructor(
if (value != field) {
field = value
mediaFrame.layoutDirection =
- if (value) View.LAYOUT_DIRECTION_RTL else View.LAYOUT_DIRECTION_LTR
+ if (value) View.LAYOUT_DIRECTION_RTL else View.LAYOUT_DIRECTION_LTR
mediaCarouselScrollHandler.scrollToStart()
}
}
@@ -168,40 +167,45 @@ class MediaCarouselController @Inject constructor(
const val PAGINATION_DELAY = 1900f
const val MEDIATITLES_DELAY = 1000f
const val MEDIACONTAINERS_DELAY = 967f
- val TRANSFORM_BEZIER = PathInterpolator (0.68F, 0F, 0F, 1F)
- val REVERSE_BEZIER = PathInterpolator (0F, 0.68F, 1F, 0F)
+ val TRANSFORM_BEZIER = PathInterpolator(0.68F, 0F, 0F, 1F)
+ val REVERSE_BEZIER = PathInterpolator(0F, 0.68F, 1F, 0F)
fun calculateAlpha(squishinessFraction: Float, delay: Float, duration: Float): Float {
val transformStartFraction = delay / ANIMATION_BASE_DURATION
val transformDurationFraction = duration / ANIMATION_BASE_DURATION
val squishinessToTime = REVERSE_BEZIER.getInterpolation(squishinessFraction)
- return MathUtils.constrain((squishinessToTime - transformStartFraction) /
- transformDurationFraction, 0F, 1F)
+ return MathUtils.constrain(
+ (squishinessToTime - transformStartFraction) / transformDurationFraction,
+ 0F,
+ 1F
+ )
}
}
- private val configListener = object : ConfigurationController.ConfigurationListener {
- override fun onDensityOrFontScaleChanged() {
- // System font changes should only happen when UMO is offscreen or a flicker may occur
- updatePlayers(recreateMedia = true)
- inflateSettingsButton()
- }
+ private val configListener =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onDensityOrFontScaleChanged() {
+ // System font changes should only happen when UMO is offscreen or a flicker may
+ // occur
+ updatePlayers(recreateMedia = true)
+ inflateSettingsButton()
+ }
- override fun onThemeChanged() {
- updatePlayers(recreateMedia = false)
- inflateSettingsButton()
- }
+ override fun onThemeChanged() {
+ updatePlayers(recreateMedia = false)
+ inflateSettingsButton()
+ }
- override fun onConfigChanged(newConfig: Configuration?) {
- if (newConfig == null) return
- isRtl = newConfig.layoutDirection == View.LAYOUT_DIRECTION_RTL
- }
+ override fun onConfigChanged(newConfig: Configuration?) {
+ if (newConfig == null) return
+ isRtl = newConfig.layoutDirection == View.LAYOUT_DIRECTION_RTL
+ }
- override fun onUiModeChanged() {
- updatePlayers(recreateMedia = false)
- inflateSettingsButton()
+ override fun onUiModeChanged() {
+ updatePlayers(recreateMedia = false)
+ inflateSettingsButton()
+ }
}
- }
/**
* Update MediaCarouselScrollHandler.visibleToUser to reflect media card container visibility.
@@ -218,10 +222,19 @@ class MediaCarouselController @Inject constructor(
mediaFrame = inflateMediaCarousel()
mediaCarousel = mediaFrame.requireViewById(R.id.media_carousel_scroller)
pageIndicator = mediaFrame.requireViewById(R.id.media_page_indicator)
- mediaCarouselScrollHandler = MediaCarouselScrollHandler(mediaCarousel, pageIndicator,
- executor, this::onSwipeToDismiss, this::updatePageIndicatorLocation,
- this::closeGuts, falsingCollector, falsingManager, this::logSmartspaceImpression,
- logger)
+ mediaCarouselScrollHandler =
+ MediaCarouselScrollHandler(
+ mediaCarousel,
+ pageIndicator,
+ executor,
+ this::onSwipeToDismiss,
+ this::updatePageIndicatorLocation,
+ this::closeGuts,
+ falsingCollector,
+ falsingManager,
+ this::logSmartspaceImpression,
+ logger
+ )
isRtl = context.resources.configuration.layoutDirection == View.LAYOUT_DIRECTION_RTL
inflateSettingsButton()
mediaContent = mediaCarousel.requireViewById(R.id.media_carousel)
@@ -232,9 +245,7 @@ class MediaCarouselController @Inject constructor(
reorderAllPlayers(previousVisiblePlayerKey = null)
}
- keysNeedRemoval.forEach {
- removePlayer(it)
- }
+ keysNeedRemoval.forEach { removePlayer(it) }
if (keysNeedRemoval.size > 0) {
// Carousel visibility may need to be updated after late removals
updateHostVisibility()
@@ -251,176 +262,226 @@ class MediaCarouselController @Inject constructor(
mediaCarouselScrollHandler.scrollToStart()
}
visualStabilityProvider.addPersistentReorderingAllowedListener(visualStabilityCallback)
- mediaManager.addListener(object : MediaDataManager.Listener {
- override fun onMediaDataLoaded(
- key: String,
- oldKey: String?,
- data: MediaData,
- immediately: Boolean,
- receivedSmartspaceCardLatency: Int,
- isSsReactivated: Boolean
- ) {
- debugLogger.logMediaLoaded(key)
- if (addOrUpdatePlayer(key, oldKey, data, isSsReactivated)) {
- // Log card received if a new resumable media card is added
- MediaPlayerData.getMediaPlayer(key)?.let {
- /* ktlint-disable max-line-length */
- logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
+ mediaManager.addListener(
+ object : MediaDataManager.Listener {
+ override fun onMediaDataLoaded(
+ key: String,
+ oldKey: String?,
+ data: MediaData,
+ immediately: Boolean,
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
+ ) {
+ debugLogger.logMediaLoaded(key)
+ if (addOrUpdatePlayer(key, oldKey, data, isSsReactivated)) {
+ // Log card received if a new resumable media card is added
+ MediaPlayerData.getMediaPlayer(key)?.let {
+ /* ktlint-disable max-line-length */
+ logSmartspaceCardReported(
+ 759, // SMARTSPACE_CARD_RECEIVED
it.mSmartspaceId,
it.mUid,
- surfaces = intArrayOf(
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY),
- rank = MediaPlayerData.getMediaPlayerIndex(key))
- /* ktlint-disable max-line-length */
- }
- if (mediaCarouselScrollHandler.visibleToUser &&
- mediaCarouselScrollHandler.visibleMediaIndex
- == MediaPlayerData.getMediaPlayerIndex(key)) {
- logSmartspaceImpression(mediaCarouselScrollHandler.qsExpanded)
- }
- } else if (receivedSmartspaceCardLatency != 0) {
- // Log resume card received if resumable media card is reactivated and
- // resume card is ranked first
- MediaPlayerData.players().forEachIndexed { index, it ->
- if (it.recommendationViewHolder == null) {
- it.mSmartspaceId = SmallHash.hash(it.mUid +
- systemClock.currentTimeMillis().toInt())
- it.mIsImpressed = false
+ surfaces =
+ intArrayOf(
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY
+ ),
+ rank = MediaPlayerData.getMediaPlayerIndex(key)
+ )
/* ktlint-disable max-line-length */
- logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
+ }
+ if (
+ mediaCarouselScrollHandler.visibleToUser &&
+ mediaCarouselScrollHandler.visibleMediaIndex ==
+ MediaPlayerData.getMediaPlayerIndex(key)
+ ) {
+ logSmartspaceImpression(mediaCarouselScrollHandler.qsExpanded)
+ }
+ } else if (receivedSmartspaceCardLatency != 0) {
+ // Log resume card received if resumable media card is reactivated and
+ // resume card is ranked first
+ MediaPlayerData.players().forEachIndexed { index, it ->
+ if (it.recommendationViewHolder == null) {
+ it.mSmartspaceId =
+ SmallHash.hash(
+ it.mUid + systemClock.currentTimeMillis().toInt()
+ )
+ it.mIsImpressed = false
+ /* ktlint-disable max-line-length */
+ logSmartspaceCardReported(
+ 759, // SMARTSPACE_CARD_RECEIVED
it.mSmartspaceId,
it.mUid,
- surfaces = intArrayOf(
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY),
+ surfaces =
+ intArrayOf(
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY
+ ),
rank = index,
- receivedLatencyMillis = receivedSmartspaceCardLatency)
- /* ktlint-disable max-line-length */
+ receivedLatencyMillis = receivedSmartspaceCardLatency
+ )
+ /* ktlint-disable max-line-length */
+ }
+ }
+ // If media container area already visible to the user, log impression for
+ // reactivated card.
+ if (
+ mediaCarouselScrollHandler.visibleToUser &&
+ !mediaCarouselScrollHandler.qsExpanded
+ ) {
+ logSmartspaceImpression(mediaCarouselScrollHandler.qsExpanded)
}
}
- // If media container area already visible to the user, log impression for
- // reactivated card.
- if (mediaCarouselScrollHandler.visibleToUser &&
- !mediaCarouselScrollHandler.qsExpanded) {
- logSmartspaceImpression(mediaCarouselScrollHandler.qsExpanded)
- }
- }
- val canRemove = data.isPlaying?.let { !it } ?: data.isClearable && !data.active
- if (canRemove && !Utils.useMediaResumption(context)) {
- // This view isn't playing, let's remove this! This happens e.g when
- // dismissing/timing out a view. We still have the data around because
- // resumption could be on, but we should save the resources and release this.
- if (isReorderingAllowed) {
- onMediaDataRemoved(key)
+ val canRemove = data.isPlaying?.let { !it } ?: data.isClearable && !data.active
+ if (canRemove && !Utils.useMediaResumption(context)) {
+ // This view isn't playing, let's remove this! This happens e.g. when
+ // dismissing/timing out a view. We still have the data around because
+ // resumption could be on, but we should save the resources and release
+ // this.
+ if (isReorderingAllowed) {
+ onMediaDataRemoved(key)
+ } else {
+ keysNeedRemoval.add(key)
+ }
} else {
- keysNeedRemoval.add(key)
+ keysNeedRemoval.remove(key)
}
- } else {
- keysNeedRemoval.remove(key)
}
- }
- override fun onSmartspaceMediaDataLoaded(
- key: String,
- data: SmartspaceMediaData,
- shouldPrioritize: Boolean
- ) {
- debugLogger.logRecommendationLoaded(key)
- // Log the case where the hidden media carousel with the existed inactive resume
- // media is shown by the Smartspace signal.
- if (data.isActive) {
- val hasActivatedExistedResumeMedia =
+ override fun onSmartspaceMediaDataLoaded(
+ key: String,
+ data: SmartspaceMediaData,
+ shouldPrioritize: Boolean
+ ) {
+ debugLogger.logRecommendationLoaded(key)
+ // Log the case where the hidden media carousel with the existed inactive resume
+ // media is shown by the Smartspace signal.
+ if (data.isActive) {
+ val hasActivatedExistedResumeMedia =
!mediaManager.hasActiveMedia() &&
- mediaManager.hasAnyMedia() &&
- shouldPrioritize
- if (hasActivatedExistedResumeMedia) {
- // Log resume card received if resumable media card is reactivated and
- // recommendation card is valid and ranked first
- MediaPlayerData.players().forEachIndexed { index, it ->
- if (it.recommendationViewHolder == null) {
- it.mSmartspaceId = SmallHash.hash(it.mUid +
- systemClock.currentTimeMillis().toInt())
- it.mIsImpressed = false
- /* ktlint-disable max-line-length */
- logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
+ mediaManager.hasAnyMedia() &&
+ shouldPrioritize
+ if (hasActivatedExistedResumeMedia) {
+ // Log resume card received if resumable media card is reactivated and
+ // recommendation card is valid and ranked first
+ MediaPlayerData.players().forEachIndexed { index, it ->
+ if (it.recommendationViewHolder == null) {
+ it.mSmartspaceId =
+ SmallHash.hash(
+ it.mUid + systemClock.currentTimeMillis().toInt()
+ )
+ it.mIsImpressed = false
+ /* ktlint-disable max-line-length */
+ logSmartspaceCardReported(
+ 759, // SMARTSPACE_CARD_RECEIVED
it.mSmartspaceId,
it.mUid,
- surfaces = intArrayOf(
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY),
+ surfaces =
+ intArrayOf(
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY
+ ),
rank = index,
- receivedLatencyMillis = (systemClock.currentTimeMillis() - data.headphoneConnectionTimeMillis).toInt())
- /* ktlint-disable max-line-length */
+ receivedLatencyMillis =
+ (systemClock.currentTimeMillis() -
+ data.headphoneConnectionTimeMillis)
+ .toInt()
+ )
+ /* ktlint-disable max-line-length */
+ }
}
}
- }
- addSmartspaceMediaRecommendations(key, data, shouldPrioritize)
- MediaPlayerData.getMediaPlayer(key)?.let {
- /* ktlint-disable max-line-length */
- logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
+ addSmartspaceMediaRecommendations(key, data, shouldPrioritize)
+ MediaPlayerData.getMediaPlayer(key)?.let {
+ /* ktlint-disable max-line-length */
+ logSmartspaceCardReported(
+ 759, // SMARTSPACE_CARD_RECEIVED
it.mSmartspaceId,
it.mUid,
- surfaces = intArrayOf(
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY),
+ surfaces =
+ intArrayOf(
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN,
+ SysUiStatsLog
+ .SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__DREAM_OVERLAY
+ ),
rank = MediaPlayerData.getMediaPlayerIndex(key),
- receivedLatencyMillis = (systemClock.currentTimeMillis() - data.headphoneConnectionTimeMillis).toInt())
- /* ktlint-disable max-line-length */
- }
- if (mediaCarouselScrollHandler.visibleToUser &&
- mediaCarouselScrollHandler.visibleMediaIndex
- == MediaPlayerData.getMediaPlayerIndex(key)) {
- logSmartspaceImpression(mediaCarouselScrollHandler.qsExpanded)
+ receivedLatencyMillis =
+ (systemClock.currentTimeMillis() -
+ data.headphoneConnectionTimeMillis)
+ .toInt()
+ )
+ /* ktlint-disable max-line-length */
+ }
+ if (
+ mediaCarouselScrollHandler.visibleToUser &&
+ mediaCarouselScrollHandler.visibleMediaIndex ==
+ MediaPlayerData.getMediaPlayerIndex(key)
+ ) {
+ logSmartspaceImpression(mediaCarouselScrollHandler.qsExpanded)
+ }
+ } else {
+ onSmartspaceMediaDataRemoved(data.targetId, immediately = true)
}
- } else {
- onSmartspaceMediaDataRemoved(data.targetId, immediately = true)
}
- }
-
- override fun onMediaDataRemoved(key: String) {
- debugLogger.logMediaRemoved(key)
- removePlayer(key)
- }
- override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
- debugLogger.logRecommendationRemoved(key, immediately)
- if (immediately || isReorderingAllowed) {
+ override fun onMediaDataRemoved(key: String) {
+ debugLogger.logMediaRemoved(key)
removePlayer(key)
- if (!immediately) {
- // Although it wasn't requested, we were able to process the removal
- // immediately since reordering is allowed. So, notify hosts to update
- if (this@MediaCarouselController::updateHostVisibility.isInitialized) {
- updateHostVisibility()
+ }
+
+ override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
+ debugLogger.logRecommendationRemoved(key, immediately)
+ if (immediately || isReorderingAllowed) {
+ removePlayer(key)
+ if (!immediately) {
+ // Although it wasn't requested, we were able to process the removal
+ // immediately since reordering is allowed. So, notify hosts to update
+ if (this@MediaCarouselController::updateHostVisibility.isInitialized) {
+ updateHostVisibility()
+ }
}
+ } else {
+ keysNeedRemoval.add(key)
}
- } else {
- keysNeedRemoval.add(key)
}
}
- })
+ )
mediaFrame.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
// The pageIndicator is not laid out yet when we get the current state update,
// Lets make sure we have the right dimensions
updatePageIndicatorLocation()
}
- mediaHostStatesManager.addCallback(object : MediaHostStatesManager.Callback {
- override fun onHostStateChanged(location: Int, mediaHostState: MediaHostState) {
- if (location == desiredLocation) {
- onDesiredLocationChanged(desiredLocation, mediaHostState, animate = false)
+ mediaHostStatesManager.addCallback(
+ object : MediaHostStatesManager.Callback {
+ override fun onHostStateChanged(location: Int, mediaHostState: MediaHostState) {
+ if (location == desiredLocation) {
+ onDesiredLocationChanged(desiredLocation, mediaHostState, animate = false)
+ }
}
}
- })
+ )
}
private fun inflateSettingsButton() {
- val settings = LayoutInflater.from(context).inflate(R.layout.media_carousel_settings_button,
- mediaFrame, false) as View
+ val settings =
+ LayoutInflater.from(context)
+ .inflate(R.layout.media_carousel_settings_button, mediaFrame, false) as View
if (this::settingsButton.isInitialized) {
mediaFrame.removeView(settingsButton)
}
@@ -434,8 +495,9 @@ class MediaCarouselController @Inject constructor(
}
private fun inflateMediaCarousel(): ViewGroup {
- val mediaCarousel = LayoutInflater.from(context).inflate(R.layout.media_carousel,
- UniqueObjectHostView(context), false) as ViewGroup
+ val mediaCarousel =
+ LayoutInflater.from(context)
+ .inflate(R.layout.media_carousel, UniqueObjectHostView(context), false) as ViewGroup
// Because this is inflated when not attached to the true view hierarchy, it resolves some
// potential issues to force that the layout direction is defined by the locale
// (rather than inherited from the parent, which would resolve to LTR when unattached).
@@ -444,16 +506,15 @@ class MediaCarouselController @Inject constructor(
}
private fun reorderAllPlayers(
- previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?,
- key: String? = null
+ previousVisiblePlayerKey: MediaPlayerData.MediaSortKey?,
+ key: String? = null
) {
mediaContent.removeAllViews()
for (mediaPlayer in MediaPlayerData.players()) {
- mediaPlayer.mediaViewHolder?.let {
- mediaContent.addView(it.player)
- } ?: mediaPlayer.recommendationViewHolder?.let {
- mediaContent.addView(it.recommendations)
- }
+ mediaPlayer.mediaViewHolder?.let { mediaContent.addView(it.player) }
+ ?: mediaPlayer.recommendationViewHolder?.let {
+ mediaContent.addView(it.recommendations)
+ }
}
mediaCarouselScrollHandler.onPlayersChanged()
MediaPlayerData.updateVisibleMediaPlayers()
@@ -463,11 +524,11 @@ class MediaCarouselController @Inject constructor(
val mediaIndex = key?.let { MediaPlayerData.getMediaPlayerIndex(it) } ?: -1
if (mediaIndex != -1) {
previousVisiblePlayerKey?.let {
- val previousVisibleIndex = MediaPlayerData.playerKeys()
- .indexOfFirst { key -> it == key }
- mediaCarouselScrollHandler
- .scrollToPlayer(previousVisibleIndex, mediaIndex)
- } ?: mediaCarouselScrollHandler.scrollToPlayer(destIndex = mediaIndex)
+ val previousVisibleIndex =
+ MediaPlayerData.playerKeys().indexOfFirst { key -> it == key }
+ mediaCarouselScrollHandler.scrollToPlayer(previousVisibleIndex, mediaIndex)
+ }
+ ?: mediaCarouselScrollHandler.scrollToPlayer(destIndex = mediaIndex)
}
}
}
@@ -478,102 +539,137 @@ class MediaCarouselController @Inject constructor(
oldKey: String?,
data: MediaData,
isSsReactivated: Boolean
- ): Boolean = traceSection("MediaCarouselController#addOrUpdatePlayer") {
- MediaPlayerData.moveIfExists(oldKey, key)
- val existingPlayer = MediaPlayerData.getMediaPlayer(key)
- val curVisibleMediaKey = MediaPlayerData.visiblePlayerKeys()
- .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
- if (existingPlayer == null) {
- val newPlayer = mediaControlPanelFactory.get()
- newPlayer.attachPlayer(MediaViewHolder.create(
- LayoutInflater.from(context), mediaContent))
- newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
- val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT)
- newPlayer.mediaViewHolder?.player?.setLayoutParams(lp)
- newPlayer.bindPlayer(data, key)
- newPlayer.setListening(currentlyExpanded)
- MediaPlayerData.addMediaPlayer(
- key, data, newPlayer, systemClock, isSsReactivated, debugLogger
- )
- updatePlayerToState(newPlayer, noAnimation = true)
- // Media data added from a recommendation card should starts playing.
- if ((shouldScrollToKey && data.isPlaying == true) ||
- (!shouldScrollToKey && data.active)) {
- reorderAllPlayers(curVisibleMediaKey, key)
+ ): Boolean =
+ traceSection("MediaCarouselController#addOrUpdatePlayer") {
+ MediaPlayerData.moveIfExists(oldKey, key)
+ val existingPlayer = MediaPlayerData.getMediaPlayer(key)
+ val curVisibleMediaKey =
+ MediaPlayerData.visiblePlayerKeys()
+ .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
+ if (existingPlayer == null) {
+ val newPlayer = mediaControlPanelFactory.get()
+ newPlayer.attachPlayer(
+ MediaViewHolder.create(LayoutInflater.from(context), mediaContent)
+ )
+ newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
+ val lp =
+ LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ newPlayer.mediaViewHolder?.player?.setLayoutParams(lp)
+ newPlayer.bindPlayer(data, key)
+ newPlayer.setListening(currentlyExpanded)
+ MediaPlayerData.addMediaPlayer(
+ key,
+ data,
+ newPlayer,
+ systemClock,
+ isSsReactivated,
+ debugLogger
+ )
+ updatePlayerToState(newPlayer, noAnimation = true)
+ // Media data added from a recommendation card should starts playing.
+ if (
+ (shouldScrollToKey && data.isPlaying == true) ||
+ (!shouldScrollToKey && data.active)
+ ) {
+ reorderAllPlayers(curVisibleMediaKey, key)
+ } else {
+ needsReordering = true
+ }
} else {
- needsReordering = true
+ existingPlayer.bindPlayer(data, key)
+ MediaPlayerData.addMediaPlayer(
+ key,
+ data,
+ existingPlayer,
+ systemClock,
+ isSsReactivated,
+ debugLogger
+ )
+ val packageName = MediaPlayerData.smartspaceMediaData?.packageName ?: String()
+ // In case of recommendations hits.
+ // Check the playing status of media player and the package name.
+ // To make sure we scroll to the right app's media player.
+ if (
+ isReorderingAllowed ||
+ shouldScrollToKey &&
+ data.isPlaying == true &&
+ packageName == data.packageName
+ ) {
+ reorderAllPlayers(curVisibleMediaKey, key)
+ } else {
+ needsReordering = true
+ }
}
- } else {
- existingPlayer.bindPlayer(data, key)
- MediaPlayerData.addMediaPlayer(
- key, data, existingPlayer, systemClock, isSsReactivated, debugLogger
- )
- val packageName = MediaPlayerData.smartspaceMediaData?.packageName ?: String()
- // In case of recommendations hits.
- // Check the playing status of media player and the package name.
- // To make sure we scroll to the right app's media player.
- if (isReorderingAllowed ||
- shouldScrollToKey &&
- data.isPlaying == true &&
- packageName == data.packageName
- ) {
- reorderAllPlayers(curVisibleMediaKey, key)
- } else {
- needsReordering = true
+ updatePageIndicator()
+ mediaCarouselScrollHandler.onPlayersChanged()
+ mediaFrame.requiresRemeasuring = true
+ // Check postcondition: mediaContent should have the same number of children as there
+ // are
+ // elements in mediaPlayers.
+ if (MediaPlayerData.players().size != mediaContent.childCount) {
+ Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync")
}
+ return existingPlayer == null
}
- updatePageIndicator()
- mediaCarouselScrollHandler.onPlayersChanged()
- mediaFrame.requiresRemeasuring = true
- // Check postcondition: mediaContent should have the same number of children as there are
- // elements in mediaPlayers.
- if (MediaPlayerData.players().size != mediaContent.childCount) {
- Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync")
- }
- return existingPlayer == null
- }
private fun addSmartspaceMediaRecommendations(
key: String,
data: SmartspaceMediaData,
shouldPrioritize: Boolean
- ) = traceSection("MediaCarouselController#addSmartspaceMediaRecommendations") {
- if (DEBUG) Log.d(TAG, "Updating smartspace target in carousel")
- if (MediaPlayerData.getMediaPlayer(key) != null) {
- Log.w(TAG, "Skip adding smartspace target in carousel")
- return
- }
+ ) =
+ traceSection("MediaCarouselController#addSmartspaceMediaRecommendations") {
+ if (DEBUG) Log.d(TAG, "Updating smartspace target in carousel")
+ if (MediaPlayerData.getMediaPlayer(key) != null) {
+ Log.w(TAG, "Skip adding smartspace target in carousel")
+ return
+ }
- val existingSmartspaceMediaKey = MediaPlayerData.smartspaceMediaKey()
- existingSmartspaceMediaKey?.let {
- val removedPlayer = MediaPlayerData.removeMediaPlayer(existingSmartspaceMediaKey, true)
- removedPlayer?.run { debugLogger.logPotentialMemoryLeak(existingSmartspaceMediaKey) }
- }
+ val existingSmartspaceMediaKey = MediaPlayerData.smartspaceMediaKey()
+ existingSmartspaceMediaKey?.let {
+ val removedPlayer =
+ MediaPlayerData.removeMediaPlayer(existingSmartspaceMediaKey, true)
+ removedPlayer?.run {
+ debugLogger.logPotentialMemoryLeak(existingSmartspaceMediaKey)
+ }
+ }
- val newRecs = mediaControlPanelFactory.get()
- newRecs.attachRecommendation(
- RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent))
- newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
- val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT)
- newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
- newRecs.bindRecommendation(data)
- val curVisibleMediaKey = MediaPlayerData.visiblePlayerKeys()
- .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
- MediaPlayerData.addMediaRecommendation(
- key, data, newRecs, shouldPrioritize, systemClock, debugLogger
- )
- updatePlayerToState(newRecs, noAnimation = true)
- reorderAllPlayers(curVisibleMediaKey)
- updatePageIndicator()
- mediaFrame.requiresRemeasuring = true
- // Check postcondition: mediaContent should have the same number of children as there are
- // elements in mediaPlayers.
- if (MediaPlayerData.players().size != mediaContent.childCount) {
- Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync")
+ val newRecs = mediaControlPanelFactory.get()
+ newRecs.attachRecommendation(
+ RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent)
+ )
+ newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
+ val lp =
+ LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
+ newRecs.bindRecommendation(data)
+ val curVisibleMediaKey =
+ MediaPlayerData.visiblePlayerKeys()
+ .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
+ MediaPlayerData.addMediaRecommendation(
+ key,
+ data,
+ newRecs,
+ shouldPrioritize,
+ systemClock,
+ debugLogger
+ )
+ updatePlayerToState(newRecs, noAnimation = true)
+ reorderAllPlayers(curVisibleMediaKey)
+ updatePageIndicator()
+ mediaFrame.requiresRemeasuring = true
+ // Check postcondition: mediaContent should have the same number of children as there
+ // are
+ // elements in mediaPlayers.
+ if (MediaPlayerData.players().size != mediaContent.childCount) {
+ Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync")
+ }
}
- }
fun removePlayer(
key: String,
@@ -585,10 +681,8 @@ class MediaCarouselController @Inject constructor(
logger.logRecommendationRemoved(it.packageName, it.instanceId)
}
}
- val removed = MediaPlayerData.removeMediaPlayer(
- key,
- dismissMediaData || dismissRecommendation
- )
+ val removed =
+ MediaPlayerData.removeMediaPlayer(key, dismissMediaData || dismissRecommendation)
removed?.apply {
mediaCarouselScrollHandler.onPrePlayerRemoved(removed)
mediaContent.removeView(removed.mediaViewHolder?.player)
@@ -609,9 +703,8 @@ class MediaCarouselController @Inject constructor(
}
private fun updatePlayers(recreateMedia: Boolean) {
- pageIndicator.tintList = ColorStateList.valueOf(
- context.getColor(R.color.media_paging_indicator)
- )
+ pageIndicator.tintList =
+ ColorStateList.valueOf(context.getColor(R.color.media_paging_indicator))
MediaPlayerData.mediaData().forEach { (key, data, isSsMediaRec) ->
if (isSsMediaRec) {
@@ -619,7 +712,10 @@ class MediaCarouselController @Inject constructor(
removePlayer(key, dismissMediaData = false, dismissRecommendation = false)
smartspaceMediaData?.let {
addSmartspaceMediaRecommendations(
- it.targetId, it, MediaPlayerData.shouldPrioritizeSs)
+ it.targetId,
+ it,
+ MediaPlayerData.shouldPrioritizeSs
+ )
}
} else {
val isSsReactivated = MediaPlayerData.isSsReactivated(key)
@@ -627,7 +723,11 @@ class MediaCarouselController @Inject constructor(
removePlayer(key, dismissMediaData = false, dismissRecommendation = false)
}
addOrUpdatePlayer(
- key = key, oldKey = null, data = data, isSsReactivated = isSsReactivated)
+ key = key,
+ oldKey = null,
+ data = data,
+ isSsReactivated = isSsReactivated
+ )
}
}
}
@@ -642,14 +742,17 @@ class MediaCarouselController @Inject constructor(
}
/**
- * Set a new interpolated state for all players. This is a state that is usually controlled
- * by a finger movement where the user drags from one state to the next.
+ * Set a new interpolated state for all players. This is a state that is usually controlled by a
+ * finger movement where the user drags from one state to the next.
*
* @param startLocation the start location of our state or -1 if this is directly set
* @param endLocation the ending location of our state.
* @param progress the progress of the transition between startLocation and endlocation. If
+ * ```
* this is not a guided transformation, this will be 1.0f
- * @param immediately should this state be applied immediately, canceling all animations?
+ * @param immediately
+ * ```
+ * should this state be applied immediately, canceling all animations?
*/
fun setCurrentState(
@MediaLocation startLocation: Int,
@@ -657,7 +760,8 @@ class MediaCarouselController @Inject constructor(
progress: Float,
immediately: Boolean
) {
- if (startLocation != currentStartLocation ||
+ if (
+ startLocation != currentStartLocation ||
endLocation != currentEndLocation ||
progress != currentTransitionProgress ||
immediately
@@ -682,7 +786,8 @@ class MediaCarouselController @Inject constructor(
// when squishing in split shade, only use endState, which keeps changing
// to provide squishFraction
val squishFraction = hostStates[currentEndLocation]?.squishFraction ?: 1.0F
- val endAlpha = (if (endIsVisible) 1.0f else 0.0f) *
+ val endAlpha =
+ (if (endIsVisible) 1.0f else 0.0f) *
calculateAlpha(squishFraction, PAGINATION_DELAY, DURATION)
var alpha = 1.0f
if (!endIsVisible || !startIsVisible) {
@@ -691,10 +796,8 @@ class MediaCarouselController @Inject constructor(
progress = 1.0f - progress
}
// Let's fade in quickly at the end where the view is visible
- progress = MathUtils.constrain(
- MathUtils.map(0.95f, 1.0f, 0.0f, 1.0f, progress),
- 0.0f,
- 1.0f)
+ progress =
+ MathUtils.constrain(MathUtils.map(0.95f, 1.0f, 0.0f, 1.0f, progress), 0.0f, 1.0f)
alpha = MathUtils.lerp(startAlpha, endAlpha, progress)
}
pageIndicator.alpha = alpha
@@ -702,20 +805,19 @@ class MediaCarouselController @Inject constructor(
private fun updatePageIndicatorLocation() {
// Update the location of the page indicator, carousel clipping
- val translationX = if (isRtl) {
- (pageIndicator.width - currentCarouselWidth) / 2.0f
- } else {
- (currentCarouselWidth - pageIndicator.width) / 2.0f
- }
+ val translationX =
+ if (isRtl) {
+ (pageIndicator.width - currentCarouselWidth) / 2.0f
+ } else {
+ (currentCarouselWidth - pageIndicator.width) / 2.0f
+ }
pageIndicator.translationX = translationX + mediaCarouselScrollHandler.contentTranslation
val layoutParams = pageIndicator.layoutParams as ViewGroup.MarginLayoutParams
- pageIndicator.translationY = (currentCarouselHeight - pageIndicator.height -
- layoutParams.bottomMargin).toFloat()
+ pageIndicator.translationY =
+ (currentCarouselHeight - pageIndicator.height - layoutParams.bottomMargin).toFloat()
}
- /**
- * Update the dimension of this carousel.
- */
+ /** Update the dimension of this carousel. */
private fun updateCarouselDimensions() {
var width = 0
var height = 0
@@ -730,7 +832,9 @@ class MediaCarouselController @Inject constructor(
currentCarouselWidth = width
currentCarouselHeight = height
mediaCarouselScrollHandler.setCarouselBounds(
- currentCarouselWidth, currentCarouselHeight)
+ currentCarouselWidth,
+ currentCarouselHeight
+ )
updatePageIndicatorLocation()
updatePageIndicatorAlpha()
}
@@ -738,13 +842,14 @@ class MediaCarouselController @Inject constructor(
private fun maybeResetSettingsCog() {
val hostStates = mediaHostStatesManager.mediaHostStates
- val endShowsActive = hostStates[currentEndLocation]?.showsOnlyActiveMedia
- ?: true
- val startShowsActive = hostStates[currentStartLocation]?.showsOnlyActiveMedia
- ?: endShowsActive
- if (currentlyShowingOnlyActive != endShowsActive ||
+ val endShowsActive = hostStates[currentEndLocation]?.showsOnlyActiveMedia ?: true
+ val startShowsActive =
+ hostStates[currentStartLocation]?.showsOnlyActiveMedia ?: endShowsActive
+ if (
+ currentlyShowingOnlyActive != endShowsActive ||
((currentTransitionProgress != 1.0f && currentTransitionProgress != 0.0f) &&
- startShowsActive != endShowsActive)) {
+ startShowsActive != endShowsActive)
+ ) {
// Whenever we're transitioning from between differing states or the endstate differs
// we reset the translation
currentlyShowingOnlyActive = endShowsActive
@@ -754,17 +859,18 @@ class MediaCarouselController @Inject constructor(
private fun updatePlayerToState(mediaPlayer: MediaControlPanel, noAnimation: Boolean) {
mediaPlayer.mediaViewController.setCurrentState(
- startLocation = currentStartLocation,
- endLocation = currentEndLocation,
- transitionProgress = currentTransitionProgress,
- applyImmediately = noAnimation)
+ startLocation = currentStartLocation,
+ endLocation = currentEndLocation,
+ transitionProgress = currentTransitionProgress,
+ applyImmediately = noAnimation
+ )
}
/**
- * The desired location of this view has changed. We should remeasure the view to match
- * the new bounds and kick off bounds animations if necessary.
- * If an animation is happening, an animation is kicked of externally, which sets a new
- * current state until we reach the targetState.
+ * The desired location of this view has changed. We should remeasure the view to match the new
+ * bounds and kick off bounds animations if necessary. If an animation is happening, an
+ * animation is kicked of externally, which sets a new current state until we reach the
+ * targetState.
*
* @param desiredLocation the location we're going to
* @param desiredHostState the target state we're transitioning to
@@ -776,64 +882,66 @@ class MediaCarouselController @Inject constructor(
animate: Boolean,
duration: Long = 200,
startDelay: Long = 0
- ) = traceSection("MediaCarouselController#onDesiredLocationChanged") {
- desiredHostState?.let {
- if (this.desiredLocation != desiredLocation) {
- // Only log an event when location changes
- logger.logCarouselPosition(desiredLocation)
- }
+ ) =
+ traceSection("MediaCarouselController#onDesiredLocationChanged") {
+ desiredHostState?.let {
+ if (this.desiredLocation != desiredLocation) {
+ // Only log an event when location changes
+ logger.logCarouselPosition(desiredLocation)
+ }
- // This is a hosting view, let's remeasure our players
- this.desiredLocation = desiredLocation
- this.desiredHostState = it
- currentlyExpanded = it.expansion > 0
+ // This is a hosting view, let's remeasure our players
+ this.desiredLocation = desiredLocation
+ this.desiredHostState = it
+ currentlyExpanded = it.expansion > 0
- val shouldCloseGuts = !currentlyExpanded &&
- !mediaManager.hasActiveMediaOrRecommendation() &&
- desiredHostState.showsOnlyActiveMedia
+ val shouldCloseGuts =
+ !currentlyExpanded &&
+ !mediaManager.hasActiveMediaOrRecommendation() &&
+ desiredHostState.showsOnlyActiveMedia
- for (mediaPlayer in MediaPlayerData.players()) {
- if (animate) {
- mediaPlayer.mediaViewController.animatePendingStateChange(
+ for (mediaPlayer in MediaPlayerData.players()) {
+ if (animate) {
+ mediaPlayer.mediaViewController.animatePendingStateChange(
duration = duration,
- delay = startDelay)
- }
- if (shouldCloseGuts && mediaPlayer.mediaViewController.isGutsVisible) {
- mediaPlayer.closeGuts(!animate)
- }
+ delay = startDelay
+ )
+ }
+ if (shouldCloseGuts && mediaPlayer.mediaViewController.isGutsVisible) {
+ mediaPlayer.closeGuts(!animate)
+ }
- mediaPlayer.mediaViewController.onLocationPreChange(desiredLocation)
- }
- mediaCarouselScrollHandler.showsSettingsButton = !it.showsOnlyActiveMedia
- mediaCarouselScrollHandler.falsingProtectionNeeded = it.falsingProtectionNeeded
- val nowVisible = it.visible
- if (nowVisible != playersVisible) {
- playersVisible = nowVisible
- if (nowVisible) {
- mediaCarouselScrollHandler.resetTranslation()
+ mediaPlayer.mediaViewController.onLocationPreChange(desiredLocation)
}
+ mediaCarouselScrollHandler.showsSettingsButton = !it.showsOnlyActiveMedia
+ mediaCarouselScrollHandler.falsingProtectionNeeded = it.falsingProtectionNeeded
+ val nowVisible = it.visible
+ if (nowVisible != playersVisible) {
+ playersVisible = nowVisible
+ if (nowVisible) {
+ mediaCarouselScrollHandler.resetTranslation()
+ }
+ }
+ updateCarouselSize()
}
- updateCarouselSize()
}
- }
fun closeGuts(immediate: Boolean = true) {
- MediaPlayerData.players().forEach {
- it.closeGuts(immediate)
- }
+ MediaPlayerData.players().forEach { it.closeGuts(immediate) }
}
- /**
- * Update the size of the carousel, remeasuring it if necessary.
- */
+ /** Update the size of the carousel, remeasuring it if necessary. */
private fun updateCarouselSize() {
val width = desiredHostState?.measurementInput?.width ?: 0
val height = desiredHostState?.measurementInput?.height ?: 0
- if (width != carouselMeasureWidth && width != 0 ||
- height != carouselMeasureHeight && height != 0) {
+ if (
+ width != carouselMeasureWidth && width != 0 ||
+ height != carouselMeasureHeight && height != 0
+ ) {
carouselMeasureWidth = width
carouselMeasureHeight = height
- val playerWidthPlusPadding = carouselMeasureWidth +
+ val playerWidthPlusPadding =
+ carouselMeasureWidth +
context.resources.getDimensionPixelSize(R.dimen.qs_media_padding)
// Let's remeasure the carousel
val widthSpec = desiredHostState?.measurementInput?.widthMeasureSpec ?: 0
@@ -845,24 +953,24 @@ class MediaCarouselController @Inject constructor(
}
}
- /**
- * Log the user impression for media card at visibleMediaIndex.
- */
+ /** Log the user impression for media card at visibleMediaIndex. */
fun logSmartspaceImpression(qsExpanded: Boolean) {
val visibleMediaIndex = mediaCarouselScrollHandler.visibleMediaIndex
if (MediaPlayerData.players().size > visibleMediaIndex) {
val mediaControlPanel = MediaPlayerData.getMediaControlPanel(visibleMediaIndex)
val hasActiveMediaOrRecommendationCard =
- MediaPlayerData.hasActiveMediaOrRecommendationCard()
+ MediaPlayerData.hasActiveMediaOrRecommendationCard()
if (!hasActiveMediaOrRecommendationCard && !qsExpanded) {
// Skip logging if on LS or QQS, and there is no active media card
return
}
mediaControlPanel?.let {
- logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
- it.mSmartspaceId,
- it.mUid,
- intArrayOf(it.surfaceForSmartspaceLogging))
+ logSmartspaceCardReported(
+ 800, // SMARTSPACE_CARD_SEEN
+ it.mSmartspaceId,
+ it.mUid,
+ intArrayOf(it.surfaceForSmartspaceLogging)
+ )
it.mIsImpressed = true
}
}
@@ -880,13 +988,12 @@ class MediaCarouselController @Inject constructor(
* the event happened
* @param interactedSubcardRank the rank for interacted media item for recommendation card, -1
* for tapping on card but not on any media item, 0 for first media item, 1 for second, etc.
- * @param interactedSubcardCardinality how many media items were shown to the user when there
- * is user interaction
+ * @param interactedSubcardCardinality how many media items were shown to the user when there is
+ * user interaction
* @param rank the rank for media card in the media carousel, starting from 0
* @param receivedLatencyMillis latency in milliseconds for card received events. E.g. latency
* between headphone connection to sysUI displays media recommendation card
* @param isSwipeToDismiss whether is to log swipe-to-dismiss event
- *
*/
fun logSmartspaceCardReported(
eventId: Int,
@@ -905,62 +1012,66 @@ class MediaCarouselController @Inject constructor(
val mediaControlKey = MediaPlayerData.visiblePlayerKeys().elementAt(rank)
// Only log media resume card when Smartspace data is available
- if (!mediaControlKey.isSsMediaRec &&
+ if (
+ !mediaControlKey.isSsMediaRec &&
!mediaManager.smartspaceMediaData.isActive &&
- MediaPlayerData.smartspaceMediaData == null) {
+ MediaPlayerData.smartspaceMediaData == null
+ ) {
return
}
val cardinality = mediaContent.getChildCount()
surfaces.forEach { surface ->
/* ktlint-disable max-line-length */
- SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED,
- eventId,
- instanceId,
- // Deprecated, replaced with AiAi feature type so we don't need to create logging
- // card type for each new feature.
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD,
- surface,
- // Use -1 as rank value to indicate user swipe to dismiss the card
- if (isSwipeToDismiss) -1 else rank,
- cardinality,
- if (mediaControlKey.isSsMediaRec)
- 15 // MEDIA_RECOMMENDATION
- else if (mediaControlKey.isSsReactivated)
- 43 // MEDIA_RESUME_SS_ACTIVATED
- else
- 31, // MEDIA_RESUME
- uid,
- interactedSubcardRank,
- interactedSubcardCardinality,
- receivedLatencyMillis,
- null, // Media cards cannot have subcards.
- null // Media cards don't have dimensions today.
+ SysUiStatsLog.write(
+ SysUiStatsLog.SMARTSPACE_CARD_REPORTED,
+ eventId,
+ instanceId,
+ // Deprecated, replaced with AiAi feature type so we don't need to create logging
+ // card type for each new feature.
+ SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD,
+ surface,
+ // Use -1 as rank value to indicate user swipe to dismiss the card
+ if (isSwipeToDismiss) -1 else rank,
+ cardinality,
+ if (mediaControlKey.isSsMediaRec) 15 // MEDIA_RECOMMENDATION
+ else if (mediaControlKey.isSsReactivated) 43 // MEDIA_RESUME_SS_ACTIVATED
+ else 31, // MEDIA_RESUME
+ uid,
+ interactedSubcardRank,
+ interactedSubcardCardinality,
+ receivedLatencyMillis,
+ null, // Media cards cannot have subcards.
+ null // Media cards don't have dimensions today.
)
/* ktlint-disable max-line-length */
if (DEBUG) {
- Log.d(TAG, "Log Smartspace card event id: $eventId instance id: $instanceId" +
+ Log.d(
+ TAG,
+ "Log Smartspace card event id: $eventId instance id: $instanceId" +
" surface: $surface rank: $rank cardinality: $cardinality " +
"isRecommendationCard: ${mediaControlKey.isSsMediaRec} " +
"isSsReactivated: ${mediaControlKey.isSsReactivated}" +
"uid: $uid " +
"interactedSubcardRank: $interactedSubcardRank " +
"interactedSubcardCardinality: $interactedSubcardCardinality " +
- "received_latency_millis: $receivedLatencyMillis")
+ "received_latency_millis: $receivedLatencyMillis"
+ )
}
}
}
private fun onSwipeToDismiss() {
- MediaPlayerData.players().forEachIndexed {
- index, it ->
+ MediaPlayerData.players().forEachIndexed { index, it ->
if (it.mIsImpressed) {
- logSmartspaceCardReported(SMARTSPACE_CARD_DISMISS_EVENT,
- it.mSmartspaceId,
- it.mUid,
- intArrayOf(it.surfaceForSmartspaceLogging),
- rank = index,
- isSwipeToDismiss = true)
+ logSmartspaceCardReported(
+ SMARTSPACE_CARD_DISMISS_EVENT,
+ it.mSmartspaceId,
+ it.mUid,
+ intArrayOf(it.surfaceForSmartspaceLogging),
+ rank = index,
+ isSwipeToDismiss = true
+ )
// Reset card impressed state when swipe to dismissed
it.mIsImpressed = false
}
@@ -971,7 +1082,9 @@ class MediaCarouselController @Inject constructor(
fun getCurrentVisibleMediaContentIntent(): PendingIntent? {
return MediaPlayerData.playerKeys()
- .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)?.data?.clickIntent
+ .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
+ ?.data
+ ?.clickIntent
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
@@ -984,15 +1097,18 @@ class MediaCarouselController @Inject constructor(
println("shouldPrioritizeSs: ${MediaPlayerData.shouldPrioritizeSs}")
println("current size: $currentCarouselWidth x $currentCarouselHeight")
println("location: $desiredLocation")
- println("state: ${desiredHostState?.expansion}, " +
- "only active ${desiredHostState?.showsOnlyActiveMedia}")
+ println(
+ "state: ${desiredHostState?.expansion}, " +
+ "only active ${desiredHostState?.showsOnlyActiveMedia}"
+ )
}
}
}
@VisibleForTesting
internal object MediaPlayerData {
- private val EMPTY = MediaData(
+ private val EMPTY =
+ MediaData(
userId = -1,
initialized = false,
app = null,
@@ -1009,7 +1125,8 @@ internal object MediaPlayerData {
active = true,
resumeAction = null,
instanceId = InstanceId.fakeInstanceId(-1),
- appUid = -1)
+ appUid = -1
+ )
// Whether should prioritize Smartspace card.
internal var shouldPrioritizeSs: Boolean = false
private set
@@ -1024,17 +1141,21 @@ internal object MediaPlayerData {
val isSsReactivated: Boolean = false
)
- private val comparator = compareByDescending<MediaSortKey> {
- it.data.isPlaying == true && it.data.playbackLocation == MediaData.PLAYBACK_LOCAL }
- .thenByDescending {
- it.data.isPlaying == true && it.data.playbackLocation == MediaData.PLAYBACK_CAST_LOCAL }
- .thenByDescending { it.data.active }
- .thenByDescending { shouldPrioritizeSs == it.isSsMediaRec }
- .thenByDescending { !it.data.resumption }
- .thenByDescending { it.data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE }
- .thenByDescending { it.data.lastActive }
- .thenByDescending { it.updateTime }
- .thenByDescending { it.data.notificationKey }
+ private val comparator =
+ compareByDescending<MediaSortKey> {
+ it.data.isPlaying == true && it.data.playbackLocation == MediaData.PLAYBACK_LOCAL
+ }
+ .thenByDescending {
+ it.data.isPlaying == true &&
+ it.data.playbackLocation == MediaData.PLAYBACK_CAST_LOCAL
+ }
+ .thenByDescending { it.data.active }
+ .thenByDescending { shouldPrioritizeSs == it.isSsMediaRec }
+ .thenByDescending { !it.data.resumption }
+ .thenByDescending { it.data.playbackLocation != MediaData.PLAYBACK_CAST_REMOTE }
+ .thenByDescending { it.data.lastActive }
+ .thenByDescending { it.updateTime }
+ .thenByDescending { it.data.notificationKey }
private val mediaPlayers = TreeMap<MediaSortKey, MediaControlPanel>(comparator)
private val mediaData: MutableMap<String, MediaSortKey> = mutableMapOf()
@@ -1053,8 +1174,14 @@ internal object MediaPlayerData {
if (removedPlayer != null && removedPlayer != player) {
debugLogger?.logPotentialMemoryLeak(key)
}
- val sortKey = MediaSortKey(isSsMediaRec = false,
- data, key, clock.currentTimeMillis(), isSsReactivated = isSsReactivated)
+ val sortKey =
+ MediaSortKey(
+ isSsMediaRec = false,
+ data,
+ key,
+ clock.currentTimeMillis(),
+ isSsReactivated = isSsReactivated
+ )
mediaData.put(key, sortKey)
mediaPlayers.put(sortKey, player)
visibleMediaPlayers.put(key, sortKey)
@@ -1073,13 +1200,14 @@ internal object MediaPlayerData {
if (removedPlayer != null && removedPlayer != player) {
debugLogger?.logPotentialMemoryLeak(key)
}
- val sortKey = MediaSortKey(
- isSsMediaRec = true,
- EMPTY.copy(isPlaying = false),
- key,
- clock.currentTimeMillis(),
- isSsReactivated = true
- )
+ val sortKey =
+ MediaSortKey(
+ isSsMediaRec = true,
+ EMPTY.copy(isPlaying = false),
+ key,
+ clock.currentTimeMillis(),
+ isSsReactivated = true
+ )
mediaData.put(key, sortKey)
mediaPlayers.put(sortKey, player)
visibleMediaPlayers.put(key, sortKey)
@@ -1126,17 +1254,19 @@ internal object MediaPlayerData {
* Removes media player given the key.
* @param isDismissed determines whether the media player is removed from the carousel.
*/
- fun removeMediaPlayer(key: String, isDismissed: Boolean = false) = mediaData.remove(key)?.let {
- if (it.isSsMediaRec) {
- smartspaceMediaData = null
- }
- if (isDismissed) {
- visibleMediaPlayers.remove(key)
+ fun removeMediaPlayer(key: String, isDismissed: Boolean = false) =
+ mediaData.remove(key)?.let {
+ if (it.isSsMediaRec) {
+ smartspaceMediaData = null
+ }
+ if (isDismissed) {
+ visibleMediaPlayers.remove(key)
+ }
+ mediaPlayers.remove(it)
}
- mediaPlayers.remove(it)
- }
- fun mediaData() = mediaData.entries.map { e -> Triple(e.key, e.value.data, e.value.isSsMediaRec) }
+ fun mediaData() =
+ mediaData.entries.map { e -> Triple(e.key, e.value.data, e.value.isSsMediaRec) }
fun dataKeys() = mediaData.keys
@@ -1187,14 +1317,11 @@ internal object MediaPlayerData {
fun isSsReactivated(key: String): Boolean = mediaData.get(key)?.isSsReactivated ?: false
/**
- * This method is called when media players are reordered.
- * To make sure we have the new version of the order of
- * media players visible to user.
+ * This method is called when media players are reordered. To make sure we have the new version
+ * of the order of media players visible to user.
*/
fun updateVisibleMediaPlayers() {
visibleMediaPlayers.clear()
- playerKeys().forEach {
- visibleMediaPlayers.put(it.key, it)
- }
+ playerKeys().forEach { visibleMediaPlayers.put(it.key, it) }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
index 21e3da9f3dc8..eed1bd743938 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselControllerLogger.kt
@@ -24,53 +24,43 @@ import javax.inject.Inject
/** A debug logger for [MediaCarouselController]. */
@SysUISingleton
-class MediaCarouselControllerLogger @Inject constructor(
- @MediaCarouselControllerLog private val buffer: LogBuffer
-) {
+class MediaCarouselControllerLogger
+@Inject
+constructor(@MediaCarouselControllerLog private val buffer: LogBuffer) {
/**
* Log that there might be a potential memory leak for the [MediaControlPanel] and/or
* [MediaViewController] related to [key].
*/
- fun logPotentialMemoryLeak(key: String) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- { str1 = key },
- {
- "Potential memory leak: " +
+ fun logPotentialMemoryLeak(key: String) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ { str1 = key },
+ {
+ "Potential memory leak: " +
"Removing control panel for $str1 from map without calling #onDestroy"
- }
- )
+ }
+ )
- fun logMediaLoaded(key: String) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- { str1 = key },
- { "add player $str1" }
- )
+ fun logMediaLoaded(key: String) =
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = key }, { "add player $str1" })
- fun logMediaRemoved(key: String) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- { str1 = key },
- { "removing player $str1" }
- )
+ fun logMediaRemoved(key: String) =
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = key }, { "removing player $str1" })
- fun logRecommendationLoaded(key: String) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- { str1 = key },
- { "add recommendation $str1" }
- )
+ fun logRecommendationLoaded(key: String) =
+ buffer.log(TAG, LogLevel.DEBUG, { str1 = key }, { "add recommendation $str1" })
- fun logRecommendationRemoved(key: String, immediately: Boolean) = buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = key
- bool1 = immediately
- },
- { "removing recommendation $str1, immediate=$bool1" }
- )
+ fun logRecommendationRemoved(key: String, immediately: Boolean) =
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = key
+ bool1 = immediately
+ },
+ { "removing recommendation $str1, immediate=$bool1" }
+ )
}
private const val TAG = "MediaCarouselCtlrLog"
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
index 1257e05a06a6..36b2eda65fab 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselScrollHandler.kt
@@ -44,16 +44,13 @@ private const val RUBBERBAND_FACTOR = 0.2f
private const val SETTINGS_BUTTON_TRANSLATION_FRACTION = 0.3f
/**
- * Default spring configuration to use for animations where stiffness and/or damping ratio
- * were not provided, and a default spring was not set via [PhysicsAnimator.setDefaultSpringConfig].
+ * Default spring configuration to use for animations where stiffness and/or damping ratio were not
+ * provided, and a default spring was not set via [PhysicsAnimator.setDefaultSpringConfig].
*/
-private val translationConfig = PhysicsAnimator.SpringConfig(
- SpringForce.STIFFNESS_LOW,
- SpringForce.DAMPING_RATIO_LOW_BOUNCY)
+private val translationConfig =
+ PhysicsAnimator.SpringConfig(SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_LOW_BOUNCY)
-/**
- * A controller class for the media scrollview, responsible for touch handling
- */
+/** A controller class for the media scrollview, responsible for touch handling */
class MediaCarouselScrollHandler(
private val scrollView: MediaScrollView,
private val pageIndicator: PageIndicator,
@@ -66,57 +63,36 @@ class MediaCarouselScrollHandler(
private val logSmartspaceImpression: (Boolean) -> Unit,
private val logger: MediaUiEventLogger
) {
- /**
- * Is the view in RTL
- */
- val isRtl: Boolean get() = scrollView.isLayoutRtl
- /**
- * Do we need falsing protection?
- */
+ /** Is the view in RTL */
+ val isRtl: Boolean
+ get() = scrollView.isLayoutRtl
+ /** Do we need falsing protection? */
var falsingProtectionNeeded: Boolean = false
- /**
- * The width of the carousel
- */
+ /** The width of the carousel */
private var carouselWidth: Int = 0
- /**
- * The height of the carousel
- */
+ /** The height of the carousel */
private var carouselHeight: Int = 0
- /**
- * How much are we scrolled into the current media?
- */
+ /** How much are we scrolled into the current media? */
private var cornerRadius: Int = 0
- /**
- * The content where the players are added
- */
+ /** The content where the players are added */
private var mediaContent: ViewGroup
- /**
- * The gesture detector to detect touch gestures
- */
+ /** The gesture detector to detect touch gestures */
private val gestureDetector: GestureDetectorCompat
- /**
- * The settings button view
- */
+ /** The settings button view */
private lateinit var settingsButton: View
- /**
- * What's the currently visible player index?
- */
+ /** What's the currently visible player index? */
var visibleMediaIndex: Int = 0
private set
- /**
- * How much are we scrolled into the current media?
- */
+ /** How much are we scrolled into the current media? */
private var scrollIntoCurrentMedia: Int = 0
- /**
- * how much is the content translated in X
- */
+ /** how much is the content translated in X */
var contentTranslation = 0.0f
private set(value) {
field = value
@@ -126,9 +102,7 @@ class MediaCarouselScrollHandler(
updateClipToOutline()
}
- /**
- * The width of a player including padding
- */
+ /** The width of a player including padding */
var playerWidthPlusPadding: Int = 0
set(value) {
field = value
@@ -136,82 +110,75 @@ class MediaCarouselScrollHandler(
// it's still at the same place
var newRelativeScroll = visibleMediaIndex * playerWidthPlusPadding
if (scrollIntoCurrentMedia > playerWidthPlusPadding) {
- newRelativeScroll += playerWidthPlusPadding -
- (scrollIntoCurrentMedia - playerWidthPlusPadding)
+ newRelativeScroll +=
+ playerWidthPlusPadding - (scrollIntoCurrentMedia - playerWidthPlusPadding)
} else {
newRelativeScroll += scrollIntoCurrentMedia
}
scrollView.relativeScrollX = newRelativeScroll
}
- /**
- * Does the dismiss currently show the setting cog?
- */
+ /** Does the dismiss currently show the setting cog? */
var showsSettingsButton: Boolean = false
- /**
- * A utility to detect gestures, used in the touch listener
- */
- private val gestureListener = object : GestureDetector.SimpleOnGestureListener() {
- override fun onFling(
- eStart: MotionEvent?,
- eCurrent: MotionEvent?,
- vX: Float,
- vY: Float
- ) = onFling(vX, vY)
-
- override fun onScroll(
- down: MotionEvent?,
- lastMotion: MotionEvent?,
- distanceX: Float,
- distanceY: Float
- ) = onScroll(down!!, lastMotion!!, distanceX)
-
- override fun onDown(e: MotionEvent?): Boolean {
- if (falsingProtectionNeeded) {
- falsingCollector.onNotificationStartDismissing()
+ /** A utility to detect gestures, used in the touch listener */
+ private val gestureListener =
+ object : GestureDetector.SimpleOnGestureListener() {
+ override fun onFling(
+ eStart: MotionEvent?,
+ eCurrent: MotionEvent?,
+ vX: Float,
+ vY: Float
+ ) = onFling(vX, vY)
+
+ override fun onScroll(
+ down: MotionEvent?,
+ lastMotion: MotionEvent?,
+ distanceX: Float,
+ distanceY: Float
+ ) = onScroll(down!!, lastMotion!!, distanceX)
+
+ override fun onDown(e: MotionEvent?): Boolean {
+ if (falsingProtectionNeeded) {
+ falsingCollector.onNotificationStartDismissing()
+ }
+ return false
}
- return false
}
- }
- /**
- * The touch listener for the scroll view
- */
- private val touchListener = object : Gefingerpoken {
- override fun onTouchEvent(motionEvent: MotionEvent?) = onTouch(motionEvent!!)
- override fun onInterceptTouchEvent(ev: MotionEvent?) = onInterceptTouch(ev!!)
- }
+ /** The touch listener for the scroll view */
+ private val touchListener =
+ object : Gefingerpoken {
+ override fun onTouchEvent(motionEvent: MotionEvent?) = onTouch(motionEvent!!)
+ override fun onInterceptTouchEvent(ev: MotionEvent?) = onInterceptTouch(ev!!)
+ }
- /**
- * A listener that is invoked when the scrolling changes to update player visibilities
- */
- private val scrollChangedListener = object : View.OnScrollChangeListener {
- override fun onScrollChange(
- v: View?,
- scrollX: Int,
- scrollY: Int,
- oldScrollX: Int,
- oldScrollY: Int
- ) {
- if (playerWidthPlusPadding == 0) {
- return
- }
+ /** A listener that is invoked when the scrolling changes to update player visibilities */
+ private val scrollChangedListener =
+ object : View.OnScrollChangeListener {
+ override fun onScrollChange(
+ v: View?,
+ scrollX: Int,
+ scrollY: Int,
+ oldScrollX: Int,
+ oldScrollY: Int
+ ) {
+ if (playerWidthPlusPadding == 0) {
+ return
+ }
- val relativeScrollX = scrollView.relativeScrollX
- onMediaScrollingChanged(relativeScrollX / playerWidthPlusPadding,
- relativeScrollX % playerWidthPlusPadding)
+ val relativeScrollX = scrollView.relativeScrollX
+ onMediaScrollingChanged(
+ relativeScrollX / playerWidthPlusPadding,
+ relativeScrollX % playerWidthPlusPadding
+ )
+ }
}
- }
- /**
- * Whether the media card is visible to user if any
- */
+ /** Whether the media card is visible to user if any */
var visibleToUser: Boolean = false
- /**
- * Whether the quick setting is expanded or not
- */
+ /** Whether the quick setting is expanded or not */
var qsExpanded: Boolean = false
init {
@@ -220,47 +187,61 @@ class MediaCarouselScrollHandler(
scrollView.setOverScrollMode(View.OVER_SCROLL_NEVER)
mediaContent = scrollView.contentContainer
scrollView.setOnScrollChangeListener(scrollChangedListener)
- scrollView.outlineProvider = object : ViewOutlineProvider() {
- override fun getOutline(view: View?, outline: Outline?) {
- outline?.setRoundRect(0, 0, carouselWidth, carouselHeight, cornerRadius.toFloat())
+ scrollView.outlineProvider =
+ object : ViewOutlineProvider() {
+ override fun getOutline(view: View?, outline: Outline?) {
+ outline?.setRoundRect(
+ 0,
+ 0,
+ carouselWidth,
+ carouselHeight,
+ cornerRadius.toFloat()
+ )
+ }
}
- }
}
fun onSettingsButtonUpdated(button: View) {
settingsButton = button
// We don't have a context to resolve, lets use the settingsbuttons one since that is
// reinflated appropriately
- cornerRadius = settingsButton.resources.getDimensionPixelSize(
- Utils.getThemeAttr(settingsButton.context, android.R.attr.dialogCornerRadius))
+ cornerRadius =
+ settingsButton.resources.getDimensionPixelSize(
+ Utils.getThemeAttr(settingsButton.context, android.R.attr.dialogCornerRadius)
+ )
updateSettingsPresentation()
scrollView.invalidateOutline()
}
private fun updateSettingsPresentation() {
if (showsSettingsButton && settingsButton.width > 0) {
- val settingsOffset = MathUtils.map(
+ val settingsOffset =
+ MathUtils.map(
0.0f,
getMaxTranslation().toFloat(),
0.0f,
1.0f,
- Math.abs(contentTranslation))
- val settingsTranslation = (1.0f - settingsOffset) * -settingsButton.width *
+ Math.abs(contentTranslation)
+ )
+ val settingsTranslation =
+ (1.0f - settingsOffset) *
+ -settingsButton.width *
SETTINGS_BUTTON_TRANSLATION_FRACTION
- val newTranslationX = if (isRtl) {
- // In RTL, the 0-placement is on the right side of the view, not the left...
- if (contentTranslation > 0) {
- -(scrollView.width - settingsTranslation - settingsButton.width)
- } else {
- -settingsTranslation
- }
- } else {
- if (contentTranslation > 0) {
- settingsTranslation
+ val newTranslationX =
+ if (isRtl) {
+ // In RTL, the 0-placement is on the right side of the view, not the left...
+ if (contentTranslation > 0) {
+ -(scrollView.width - settingsTranslation - settingsButton.width)
+ } else {
+ -settingsTranslation
+ }
} else {
- scrollView.width - settingsTranslation - settingsButton.width
+ if (contentTranslation > 0) {
+ settingsTranslation
+ } else {
+ scrollView.width - settingsTranslation - settingsButton.width
+ }
}
- }
val rotation = (1.0f - settingsOffset) * 50
settingsButton.rotation = rotation * -Math.signum(contentTranslation)
val alpha = MathUtils.saturate(MathUtils.map(0.5f, 1.0f, 0.0f, 1.0f, settingsOffset))
@@ -307,16 +288,14 @@ class MediaCarouselScrollHandler(
val newScrollX = scrollView.relativeScrollX + dx
// Delay the scrolling since scrollView calls springback which cancels
// the animation again..
- mainExecutor.execute {
- scrollView.smoothScrollTo(newScrollX, scrollView.scrollY)
- }
+ mainExecutor.execute { scrollView.smoothScrollTo(newScrollX, scrollView.scrollY) }
}
val currentTranslation = scrollView.getContentTranslation()
if (currentTranslation != 0.0f) {
// We started a Swipe but didn't end up with a fling. Let's either go to the
// dismissed position or go back.
- val springBack = Math.abs(currentTranslation) < getMaxTranslation() / 2 ||
- isFalseTouch()
+ val springBack =
+ Math.abs(currentTranslation) < getMaxTranslation() / 2 || isFalseTouch()
val newTranslation: Float
if (springBack) {
newTranslation = 0.0f
@@ -325,13 +304,17 @@ class MediaCarouselScrollHandler(
if (!showsSettingsButton) {
// Delay the dismiss a bit to avoid too much overlap. Waiting until the
// animation has finished also feels a bit too slow here.
- mainExecutor.executeDelayed({
- dismissCallback.invoke()
- }, DISMISS_DELAY)
+ mainExecutor.executeDelayed({ dismissCallback.invoke() }, DISMISS_DELAY)
}
}
- PhysicsAnimator.getInstance(this).spring(CONTENT_TRANSLATION,
- newTranslation, startVelocity = 0.0f, config = translationConfig).start()
+ PhysicsAnimator.getInstance(this)
+ .spring(
+ CONTENT_TRANSLATION,
+ newTranslation,
+ startVelocity = 0.0f,
+ config = translationConfig
+ )
+ .start()
scrollView.animationTargetX = newTranslation
}
}
@@ -339,10 +322,11 @@ class MediaCarouselScrollHandler(
return false
}
- private fun isFalseTouch() = falsingProtectionNeeded &&
- falsingManager.isFalseTouch(NOTIFICATION_DISMISS)
+ private fun isFalseTouch() =
+ falsingProtectionNeeded && falsingManager.isFalseTouch(NOTIFICATION_DISMISS)
- private fun getMaxTranslation() = if (showsSettingsButton) {
+ private fun getMaxTranslation() =
+ if (showsSettingsButton) {
settingsButton.width
} else {
playerWidthPlusPadding
@@ -352,15 +336,10 @@ class MediaCarouselScrollHandler(
return gestureDetector.onTouchEvent(motionEvent)
}
- fun onScroll(
- down: MotionEvent,
- lastMotion: MotionEvent,
- distanceX: Float
- ): Boolean {
+ fun onScroll(down: MotionEvent, lastMotion: MotionEvent, distanceX: Float): Boolean {
val totalX = lastMotion.x - down.x
val currentTranslation = scrollView.getContentTranslation()
- if (currentTranslation != 0.0f ||
- !scrollView.canScrollHorizontally((-totalX).toInt())) {
+ if (currentTranslation != 0.0f || !scrollView.canScrollHorizontally((-totalX).toInt())) {
var newTranslation = currentTranslation - distanceX
val absTranslation = Math.abs(newTranslation)
if (absTranslation > getMaxTranslation()) {
@@ -374,14 +353,18 @@ class MediaCarouselScrollHandler(
newTranslation = currentTranslation - distanceX * RUBBERBAND_FACTOR
} else {
// We just crossed the boundary, let's rubberband it all
- newTranslation = Math.signum(newTranslation) * (getMaxTranslation() +
- (absTranslation - getMaxTranslation()) * RUBBERBAND_FACTOR)
+ newTranslation =
+ Math.signum(newTranslation) *
+ (getMaxTranslation() +
+ (absTranslation - getMaxTranslation()) * RUBBERBAND_FACTOR)
}
} // Otherwise we don't have do do anything, and will remove the unrubberbanded
// translation
}
- if (Math.signum(newTranslation) != Math.signum(currentTranslation) &&
- currentTranslation != 0.0f) {
+ if (
+ Math.signum(newTranslation) != Math.signum(currentTranslation) &&
+ currentTranslation != 0.0f
+ ) {
// We crossed the 0.0 threshold of the translation. Let's see if we're allowed
// to scroll into the new direction
if (scrollView.canScrollHorizontally(-newTranslation.toInt())) {
@@ -392,8 +375,14 @@ class MediaCarouselScrollHandler(
}
val physicsAnimator = PhysicsAnimator.getInstance(this)
if (physicsAnimator.isRunning()) {
- physicsAnimator.spring(CONTENT_TRANSLATION,
- newTranslation, startVelocity = 0.0f, config = translationConfig).start()
+ physicsAnimator
+ .spring(
+ CONTENT_TRANSLATION,
+ newTranslation,
+ startVelocity = 0.0f,
+ config = translationConfig
+ )
+ .start()
} else {
contentTranslation = newTranslation
}
@@ -403,10 +392,7 @@ class MediaCarouselScrollHandler(
return false
}
- private fun onFling(
- vX: Float,
- vY: Float
- ): Boolean {
+ private fun onFling(vX: Float, vY: Float): Boolean {
if (vX * vX < 0.5 * vY * vY) {
return false
}
@@ -425,13 +411,17 @@ class MediaCarouselScrollHandler(
// Delay the dismiss a bit to avoid too much overlap. Waiting until the animation
// has finished also feels a bit too slow here.
if (!showsSettingsButton) {
- mainExecutor.executeDelayed({
- dismissCallback.invoke()
- }, DISMISS_DELAY)
+ mainExecutor.executeDelayed({ dismissCallback.invoke() }, DISMISS_DELAY)
}
}
- PhysicsAnimator.getInstance(this).spring(CONTENT_TRANSLATION,
- newTranslation, startVelocity = vX, config = translationConfig).start()
+ PhysicsAnimator.getInstance(this)
+ .spring(
+ CONTENT_TRANSLATION,
+ newTranslation,
+ startVelocity = vX,
+ config = translationConfig
+ )
+ .start()
scrollView.animationTargetX = newTranslation
} else {
// We're flinging the player! Let's go either to the previous or to the next player
@@ -444,21 +434,18 @@ class MediaCarouselScrollHandler(
val view = mediaContent.getChildAt(destIndex)
// We need to post this since we're dispatching a touch to the underlying view to cancel
// but canceling will actually abort the animation.
- mainExecutor.execute {
- scrollView.smoothScrollTo(view.left, scrollView.scrollY)
- }
+ mainExecutor.execute { scrollView.smoothScrollTo(view.left, scrollView.scrollY) }
}
return true
}
- /**
- * Reset the translation of the players when swiped
- */
+ /** Reset the translation of the players when swiped */
fun resetTranslation(animate: Boolean = false) {
if (scrollView.getContentTranslation() != 0.0f) {
if (animate) {
- PhysicsAnimator.getInstance(this).spring(CONTENT_TRANSLATION,
- 0.0f, config = translationConfig).start()
+ PhysicsAnimator.getInstance(this)
+ .spring(CONTENT_TRANSLATION, 0.0f, config = translationConfig)
+ .start()
scrollView.animationTargetX = 0.0f
} else {
PhysicsAnimator.getInstance(this).cancel()
@@ -486,21 +473,22 @@ class MediaCarouselScrollHandler(
closeGuts(false)
updatePlayerVisibilities()
}
- val relativeLocation = visibleMediaIndex.toFloat() + if (playerWidthPlusPadding > 0)
- scrollInAmount.toFloat() / playerWidthPlusPadding else 0f
+ val relativeLocation =
+ visibleMediaIndex.toFloat() +
+ if (playerWidthPlusPadding > 0) scrollInAmount.toFloat() / playerWidthPlusPadding
+ else 0f
// Fix the location, because PageIndicator does not handle RTL internally
- val location = if (isRtl) {
- mediaContent.childCount - relativeLocation - 1
- } else {
- relativeLocation
- }
+ val location =
+ if (isRtl) {
+ mediaContent.childCount - relativeLocation - 1
+ } else {
+ relativeLocation
+ }
pageIndicator.setLocation(location)
updateClipToOutline()
}
- /**
- * Notified whenever the players or their order has changed
- */
+ /** Notified whenever the players or their order has changed */
fun onPlayersChanged() {
updatePlayerVisibilities()
updateMediaPaddings()
@@ -530,8 +518,8 @@ class MediaCarouselScrollHandler(
}
/**
- * Notify that a player will be removed right away. This gives us the opporunity to look
- * where it was and update our scroll position.
+ * Notify that a player will be removed right away. This gives us the opporunity to look where
+ * it was and update our scroll position.
*/
fun onPrePlayerRemoved(removed: MediaControlPanel) {
val removedIndex = mediaContent.indexOfChild(removed.mediaViewHolder?.player)
@@ -551,9 +539,7 @@ class MediaCarouselScrollHandler(
}
}
- /**
- * Update the bounds of the carousel
- */
+ /** Update the bounds of the carousel */
fun setCarouselBounds(currentCarouselWidth: Int, currentCarouselHeight: Int) {
if (currentCarouselHeight != carouselHeight || currentCarouselWidth != carouselHeight) {
carouselWidth = currentCarouselWidth
@@ -562,9 +548,7 @@ class MediaCarouselScrollHandler(
}
}
- /**
- * Reset the MediaScrollView to the start.
- */
+ /** Reset the MediaScrollView to the start. */
fun scrollToStart() {
scrollView.relativeScrollX = 0
}
@@ -582,21 +566,22 @@ class MediaCarouselScrollHandler(
val destIndex = Math.min(mediaContent.getChildCount() - 1, destIndex)
val view = mediaContent.getChildAt(destIndex)
// We need to post this to wait for the active player becomes visible.
- mainExecutor.executeDelayed({
- scrollView.smoothScrollTo(view.left, scrollView.scrollY)
- }, SCROLL_DELAY)
+ mainExecutor.executeDelayed(
+ { scrollView.smoothScrollTo(view.left, scrollView.scrollY) },
+ SCROLL_DELAY
+ )
}
companion object {
- private val CONTENT_TRANSLATION = object : FloatPropertyCompat<MediaCarouselScrollHandler>(
- "contentTranslation") {
- override fun getValue(handler: MediaCarouselScrollHandler): Float {
- return handler.contentTranslation
- }
+ private val CONTENT_TRANSLATION =
+ object : FloatPropertyCompat<MediaCarouselScrollHandler>("contentTranslation") {
+ override fun getValue(handler: MediaCarouselScrollHandler): Float {
+ return handler.contentTranslation
+ }
- override fun setValue(handler: MediaCarouselScrollHandler, value: Float) {
- handler.contentTranslation = value
+ override fun setValue(handler: MediaCarouselScrollHandler, value: Float) {
+ handler.contentTranslation = value
+ }
}
- }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index e17c1608929c..6b46d8f30cad 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -59,9 +59,7 @@ import javax.inject.Inject
private val TAG: String = MediaHierarchyManager::class.java.simpleName
-/**
- * Similarly to isShown but also excludes views that have 0 alpha
- */
+/** Similarly to isShown but also excludes views that have 0 alpha */
val View.isShownNotFaded: Boolean
get() {
var current: View = this
@@ -86,7 +84,9 @@ val View.isShownNotFaded: Boolean
* and animate the positions of the views to achieve seamless transitions.
*/
@SysUISingleton
-class MediaHierarchyManager @Inject constructor(
+class MediaHierarchyManager
+@Inject
+constructor(
private val context: Context,
private val statusBarStateController: SysuiStatusBarStateController,
private val keyguardStateController: KeyguardStateController,
@@ -101,12 +101,10 @@ class MediaHierarchyManager @Inject constructor(
@Main private val handler: Handler,
) {
- /**
- * Track the media player setting status on lock screen.
- */
+ /** Track the media player setting status on lock screen. */
private var allowMediaPlayerOnLockScreen: Boolean = true
private val lockScreenMediaPlayerUri =
- secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
+ secureSettings.getUriFor(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN)
/**
* Whether we "skip" QQS during panel expansion.
@@ -118,8 +116,8 @@ class MediaHierarchyManager @Inject constructor(
/**
* 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
- * view is always in its final state when it is attached to a view host.
+ * whenever the view is transitioning from one host to another. It also make sure that the view
+ * is always in its final state when it is attached to a view host.
*/
private var rootOverlay: ViewGroupOverlay? = null
@@ -138,69 +136,68 @@ class MediaHierarchyManager @Inject constructor(
*/
private var animationStartCrossFadeProgress = 0.0f
- /**
- * The starting alpha of the animation
- */
+ /** The starting alpha of the animation */
private var animationStartAlpha = 0.0f
- /**
- * The starting location of the cross fade if an animation is running right now.
- */
- @MediaLocation
- private var crossFadeAnimationStartLocation = -1
+ /** The starting location of the cross fade if an animation is running right now. */
+ @MediaLocation private var crossFadeAnimationStartLocation = -1
- /**
- * The end location of the cross fade if an animation is running right now.
- */
- @MediaLocation
- private var crossFadeAnimationEndLocation = -1
+ /** The end location of the cross fade if an animation is running right now. */
+ @MediaLocation private var crossFadeAnimationEndLocation = -1
private var targetBounds: Rect = Rect()
private val mediaFrame
get() = mediaCarouselController.mediaFrame
private var statusbarState: Int = statusBarStateController.state
- private var animator = ValueAnimator.ofFloat(0.0f, 1.0f).apply {
- interpolator = Interpolators.FAST_OUT_SLOW_IN
- addUpdateListener {
- updateTargetState()
- val currentAlpha: Float
- var boundsProgress = animatedFraction
- if (isCrossFadeAnimatorRunning) {
- animationCrossFadeProgress = MathUtils.lerp(animationStartCrossFadeProgress, 1.0f,
- animatedFraction)
- // When crossfading, let's keep the bounds at the right location during fading
- boundsProgress = if (animationCrossFadeProgress < 0.5f) 0.0f else 1.0f
- currentAlpha = calculateAlphaFromCrossFade(animationCrossFadeProgress)
- } else {
- // If we're not crossfading, let's interpolate from the start alpha to 1.0f
- currentAlpha = MathUtils.lerp(animationStartAlpha, 1.0f, animatedFraction)
+ private var animator =
+ ValueAnimator.ofFloat(0.0f, 1.0f).apply {
+ interpolator = Interpolators.FAST_OUT_SLOW_IN
+ addUpdateListener {
+ updateTargetState()
+ val currentAlpha: Float
+ var boundsProgress = animatedFraction
+ if (isCrossFadeAnimatorRunning) {
+ animationCrossFadeProgress =
+ MathUtils.lerp(animationStartCrossFadeProgress, 1.0f, animatedFraction)
+ // When crossfading, let's keep the bounds at the right location during fading
+ boundsProgress = if (animationCrossFadeProgress < 0.5f) 0.0f else 1.0f
+ currentAlpha = calculateAlphaFromCrossFade(animationCrossFadeProgress)
+ } else {
+ // If we're not crossfading, let's interpolate from the start alpha to 1.0f
+ currentAlpha = MathUtils.lerp(animationStartAlpha, 1.0f, animatedFraction)
+ }
+ interpolateBounds(
+ animationStartBounds,
+ targetBounds,
+ boundsProgress,
+ result = currentBounds
+ )
+ resolveClipping(currentClipping)
+ applyState(currentBounds, currentAlpha, clipBounds = currentClipping)
}
- interpolateBounds(animationStartBounds, targetBounds, boundsProgress,
- result = currentBounds)
- resolveClipping(currentClipping)
- applyState(currentBounds, currentAlpha, clipBounds = currentClipping)
- }
- addListener(object : AnimatorListenerAdapter() {
- private var cancelled: Boolean = false
+ addListener(
+ object : AnimatorListenerAdapter() {
+ private var cancelled: Boolean = false
+
+ override fun onAnimationCancel(animation: Animator?) {
+ cancelled = true
+ animationPending = false
+ rootView?.removeCallbacks(startAnimation)
+ }
- override fun onAnimationCancel(animation: Animator?) {
- cancelled = true
- animationPending = false
- rootView?.removeCallbacks(startAnimation)
- }
+ override fun onAnimationEnd(animation: Animator?) {
+ isCrossFadeAnimatorRunning = false
+ if (!cancelled) {
+ applyTargetStateIfNotAnimating()
+ }
+ }
- override fun onAnimationEnd(animation: Animator?) {
- isCrossFadeAnimatorRunning = false
- if (!cancelled) {
- applyTargetStateIfNotAnimating()
+ override fun onAnimationStart(animation: Animator?) {
+ cancelled = false
+ animationPending = false
+ }
}
- }
-
- override fun onAnimationStart(animation: Animator?) {
- cancelled = false
- animationPending = false
- }
- })
- }
+ )
+ }
private fun resolveClipping(result: Rect) {
if (animationStartClipping.isEmpty) result.set(targetClipping)
@@ -210,42 +207,31 @@ class MediaHierarchyManager @Inject constructor(
private val mediaHosts = arrayOfNulls<MediaHost>(LOCATION_DREAM_OVERLAY + 1)
/**
- * The last location where this view was at before going to the desired location. This is
- * useful for guided transitions.
+ * The last location where this view was at before going to the desired location. This is useful
+ * for guided transitions.
*/
- @MediaLocation
- private var previousLocation = -1
- /**
- * The desired location where the view will be at the end of the transition.
- */
- @MediaLocation
- private var desiredLocation = -1
+ @MediaLocation private var previousLocation = -1
+ /** The desired location where the view will be at the end of the transition. */
+ @MediaLocation private var desiredLocation = -1
/**
- * The current attachment location where the view is currently attached.
- * Usually this matches the desired location except for animations whenever a view moves
- * to the new desired location, during which it is in [IN_OVERLAY].
+ * The current attachment location where the view is currently attached. Usually this matches
+ * the desired location except for animations whenever a view moves to the new desired location,
+ * during which it is in [IN_OVERLAY].
*/
- @MediaLocation
- private var currentAttachmentLocation = -1
+ @MediaLocation private var currentAttachmentLocation = -1
private var inSplitShade = false
- /**
- * Is there any active media in the carousel?
- */
+ /** Is there any active media in the carousel? */
private var hasActiveMedia: Boolean = false
get() = mediaHosts.get(LOCATION_QQS)?.visible == true
- /**
- * Are we currently waiting on an animation to start?
- */
+ /** Are we currently waiting on an animation to start? */
private var animationPending: Boolean = false
private val startAnimation: Runnable = Runnable { animator.start() }
- /**
- * The expansion of quick settings
- */
+ /** The expansion of quick settings */
var qsExpansion: Float = 0.0f
set(value) {
if (field != value) {
@@ -258,9 +244,7 @@ class MediaHierarchyManager @Inject constructor(
}
}
- /**
- * Is quick setting expanded?
- */
+ /** Is quick setting expanded? */
var qsExpanded: Boolean = false
set(value) {
if (field != value) {
@@ -281,9 +265,8 @@ class MediaHierarchyManager @Inject constructor(
private var distanceForFullShadeTransition = 0
/**
- * The amount of progress we are currently in if we're transitioning to the full shade.
- * 0.0f means we're not transitioning yet, while 1 means we're all the way in the full
- * shade.
+ * The amount of progress we are currently in if we're transitioning to the full shade. 0.0f
+ * means we're not transitioning yet, while 1 means we're all the way in the full shade.
*/
private var fullShadeTransitionProgress = 0f
set(value) {
@@ -305,9 +288,7 @@ class MediaHierarchyManager @Inject constructor(
}
}
- /**
- * Is there currently a cross-fade animation running driven by an animator?
- */
+ /** Is there currently a cross-fade animation running driven by an animator? */
private var isCrossFadeAnimatorRunning = false
/**
@@ -316,8 +297,10 @@ class MediaHierarchyManager @Inject constructor(
* the transition starts, this will no longer return true.
*/
private val isTransitioningToFullShade: Boolean
- get() = fullShadeTransitionProgress != 0f && !bypassController.bypassEnabled &&
- statusbarState == StatusBarState.KEYGUARD
+ get() =
+ fullShadeTransitionProgress != 0f &&
+ !bypassController.bypassEnabled &&
+ statusbarState == StatusBarState.KEYGUARD
/**
* Set the amount of pixels we have currently dragged down if we're transitioning to the full
@@ -354,17 +337,13 @@ class MediaHierarchyManager @Inject constructor(
}
}
- /**
- * Are location changes currently blocked?
- */
+ /** Are location changes currently blocked? */
private val blockLocationChanges: Boolean
get() {
return goingToSleep || dozeAnimationRunning
}
- /**
- * Are we currently going to sleep
- */
+ /** Are we currently going to sleep */
private var goingToSleep: Boolean = false
set(value) {
if (field != value) {
@@ -375,9 +354,7 @@ class MediaHierarchyManager @Inject constructor(
}
}
- /**
- * Are we currently fullyAwake
- */
+ /** Are we currently fullyAwake */
private var fullyAwake: Boolean = false
set(value) {
if (field != value) {
@@ -388,9 +365,7 @@ class MediaHierarchyManager @Inject constructor(
}
}
- /**
- * Is the doze animation currently Running
- */
+ /** Is the doze animation currently Running */
private var dozeAnimationRunning: Boolean = false
private set(value) {
if (field != value) {
@@ -401,9 +376,7 @@ class MediaHierarchyManager @Inject constructor(
}
}
- /**
- * Is the dream overlay currently active
- */
+ /** Is the dream overlay currently active */
private var dreamOverlayActive: Boolean = false
private set(value) {
if (field != value) {
@@ -412,9 +385,7 @@ class MediaHierarchyManager @Inject constructor(
}
}
- /**
- * Is the dream media complication currently active
- */
+ /** Is the dream media complication currently active */
private var dreamMediaComplicationActive: Boolean = false
private set(value) {
if (field != value) {
@@ -424,16 +395,13 @@ class MediaHierarchyManager @Inject constructor(
}
/**
- * The current cross fade progress. 0.5f means it's just switching
- * between the start and the end location and the content is fully faded, while 0.75f means
- * that we're halfway faded in again in the target state.
- * This is only valid while [isCrossFadeAnimatorRunning] is true.
+ * The current cross fade progress. 0.5f means it's just switching between the start and the end
+ * location and the content is fully faded, while 0.75f means that we're halfway faded in again
+ * in the target state. This is only valid while [isCrossFadeAnimatorRunning] is true.
*/
private var animationCrossFadeProgress = 1.0f
- /**
- * The current carousel Alpha.
- */
+ /** The current carousel Alpha. */
private var carouselAlpha: Float = 1.0f
set(value) {
if (field == value) {
@@ -447,8 +415,8 @@ class MediaHierarchyManager @Inject constructor(
* Calculate the alpha of the view when given a cross-fade progress.
*
* @param crossFadeProgress The current cross fade progress. 0.5f means it's just switching
- * between the start and the end location and the content is fully faded, while 0.75f means
- * that we're halfway faded in again in the target state.
+ * between the start and the end location and the content is fully faded, while 0.75f means that
+ * we're halfway faded in again in the target state.
*/
private fun calculateAlphaFromCrossFade(crossFadeProgress: Float): Float {
if (crossFadeProgress <= 0.5f) {
@@ -460,132 +428,152 @@ class MediaHierarchyManager @Inject constructor(
init {
updateConfiguration()
- configurationController.addCallback(object : ConfigurationController.ConfigurationListener {
- override fun onConfigChanged(newConfig: Configuration?) {
- updateConfiguration()
- updateDesiredLocation(forceNoAnimation = true, forceStateUpdate = true)
- }
- })
- statusBarStateController.addCallback(object : StatusBarStateController.StateListener {
- override fun onStatePreChange(oldState: Int, newState: Int) {
- // We're updating the location before the state change happens, since we want the
- // location of the previous state to still be up to date when the animation starts
- statusbarState = newState
- updateDesiredLocation()
- }
-
- override fun onStateChanged(newState: Int) {
- updateTargetState()
- // Enters shade from lock screen
- if (newState == StatusBarState.SHADE_LOCKED && isLockScreenShadeVisibleToUser()) {
- mediaCarouselController.logSmartspaceImpression(qsExpanded)
+ configurationController.addCallback(
+ object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ updateConfiguration()
+ updateDesiredLocation(forceNoAnimation = true, forceStateUpdate = true)
}
- mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
- }
-
- override fun onDozeAmountChanged(linear: Float, eased: Float) {
- dozeAnimationRunning = linear != 0.0f && linear != 1.0f
}
+ )
+ statusBarStateController.addCallback(
+ object : StatusBarStateController.StateListener {
+ override fun onStatePreChange(oldState: Int, newState: Int) {
+ // We're updating the location before the state change happens, since we want
+ // the
+ // location of the previous state to still be up to date when the animation
+ // starts
+ statusbarState = newState
+ updateDesiredLocation()
+ }
- override fun onDozingChanged(isDozing: Boolean) {
- if (!isDozing) {
- dozeAnimationRunning = false
- // Enters lock screen from screen off
- if (isLockScreenVisibleToUser()) {
+ override fun onStateChanged(newState: Int) {
+ updateTargetState()
+ // Enters shade from lock screen
+ if (
+ newState == StatusBarState.SHADE_LOCKED && isLockScreenShadeVisibleToUser()
+ ) {
mediaCarouselController.logSmartspaceImpression(qsExpanded)
}
- } else {
- updateDesiredLocation()
- qsExpanded = false
- closeGuts()
+ mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
+ isVisibleToUser()
}
- mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
- }
- override fun onExpandedChanged(isExpanded: Boolean) {
- // Enters shade from home screen
- if (isHomeScreenShadeVisibleToUser()) {
- mediaCarouselController.logSmartspaceImpression(qsExpanded)
+ override fun onDozeAmountChanged(linear: Float, eased: Float) {
+ dozeAnimationRunning = linear != 0.0f && linear != 1.0f
}
- mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
- }
- })
- dreamOverlayStateController.addCallback(object : DreamOverlayStateController.Callback {
- override fun onComplicationsChanged() {
- dreamMediaComplicationActive = dreamOverlayStateController.complications.any {
- it is MediaDreamComplication
+ override fun onDozingChanged(isDozing: Boolean) {
+ if (!isDozing) {
+ dozeAnimationRunning = false
+ // Enters lock screen from screen off
+ if (isLockScreenVisibleToUser()) {
+ mediaCarouselController.logSmartspaceImpression(qsExpanded)
+ }
+ } else {
+ updateDesiredLocation()
+ qsExpanded = false
+ closeGuts()
+ }
+ mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
+ isVisibleToUser()
}
- }
- override fun onStateChanged() {
- dreamOverlayStateController.isOverlayActive.also { dreamOverlayActive = it }
+ override fun onExpandedChanged(isExpanded: Boolean) {
+ // Enters shade from home screen
+ if (isHomeScreenShadeVisibleToUser()) {
+ mediaCarouselController.logSmartspaceImpression(qsExpanded)
+ }
+ mediaCarouselController.mediaCarouselScrollHandler.visibleToUser =
+ isVisibleToUser()
+ }
}
- })
+ )
+
+ dreamOverlayStateController.addCallback(
+ object : DreamOverlayStateController.Callback {
+ override fun onComplicationsChanged() {
+ dreamMediaComplicationActive =
+ dreamOverlayStateController.complications.any {
+ it is MediaDreamComplication
+ }
+ }
- wakefulnessLifecycle.addObserver(object : WakefulnessLifecycle.Observer {
- override fun onFinishedGoingToSleep() {
- goingToSleep = false
+ override fun onStateChanged() {
+ dreamOverlayStateController.isOverlayActive.also { dreamOverlayActive = it }
+ }
}
+ )
- override fun onStartedGoingToSleep() {
- goingToSleep = true
- fullyAwake = false
- }
+ wakefulnessLifecycle.addObserver(
+ object : WakefulnessLifecycle.Observer {
+ override fun onFinishedGoingToSleep() {
+ goingToSleep = false
+ }
- override fun onFinishedWakingUp() {
- goingToSleep = false
- fullyAwake = true
- }
+ override fun onStartedGoingToSleep() {
+ goingToSleep = true
+ fullyAwake = false
+ }
+
+ override fun onFinishedWakingUp() {
+ goingToSleep = false
+ fullyAwake = true
+ }
- override fun onStartedWakingUp() {
- goingToSleep = false
+ override fun onStartedWakingUp() {
+ goingToSleep = false
+ }
}
- })
+ )
mediaCarouselController.updateUserVisibility = {
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
}
mediaCarouselController.updateHostVisibility = {
- mediaHosts.forEach {
- it?.updateViewVisibility()
- }
+ mediaHosts.forEach { it?.updateViewVisibility() }
}
- panelEventsEvents.registerListener(object : NotifPanelEvents.Listener {
- override fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {
- skipQqsOnExpansion = isExpandImmediateEnabled
- updateDesiredLocation()
+ panelEventsEvents.registerListener(
+ object : NotifPanelEvents.Listener {
+ override fun onExpandImmediateChanged(isExpandImmediateEnabled: Boolean) {
+ skipQqsOnExpansion = isExpandImmediateEnabled
+ updateDesiredLocation()
+ }
}
- })
+ )
- val settingsObserver: ContentObserver = object : ContentObserver(handler) {
- override fun onChange(selfChange: Boolean, uri: Uri?) {
- if (uri == lockScreenMediaPlayerUri) {
- allowMediaPlayerOnLockScreen =
+ val settingsObserver: ContentObserver =
+ object : ContentObserver(handler) {
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ if (uri == lockScreenMediaPlayerUri) {
+ allowMediaPlayerOnLockScreen =
secureSettings.getBoolForUser(
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
- true,
- UserHandle.USER_CURRENT
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ true,
+ UserHandle.USER_CURRENT
)
+ }
}
}
- }
secureSettings.registerContentObserverForUser(
- Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
- settingsObserver,
- UserHandle.USER_ALL)
+ Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN,
+ settingsObserver,
+ UserHandle.USER_ALL
+ )
}
private fun updateConfiguration() {
- distanceForFullShadeTransition = context.resources.getDimensionPixelSize(
- R.dimen.lockscreen_shade_media_transition_distance)
+ distanceForFullShadeTransition =
+ context.resources.getDimensionPixelSize(
+ R.dimen.lockscreen_shade_media_transition_distance
+ )
inSplitShade = LargeScreenUtils.shouldUseSplitNotificationShade(context.resources)
}
/**
- * Register a media host and create a view can be attached to a view hierarchy
- * and where the players will be placed in when the host is the currently desired state.
+ * Register a media host and create a view can be attached to a view hierarchy and where the
+ * players will be placed in when the host is the currently desired state.
*
* @return the hostView associated with this location
*/
@@ -613,27 +601,26 @@ class MediaHierarchyManager @Inject constructor(
return viewHost
}
- /**
- * Close the guts in all players in [MediaCarouselController].
- */
+ /** Close the guts in all players in [MediaCarouselController]. */
fun closeGuts() {
mediaCarouselController.closeGuts()
}
private fun createUniqueObjectHost(): UniqueObjectHostView {
val viewHost = UniqueObjectHostView(context)
- viewHost.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
- override fun onViewAttachedToWindow(p0: View?) {
- if (rootOverlay == null) {
- rootView = viewHost.viewRootImpl.view
- rootOverlay = (rootView!!.overlay as ViewGroupOverlay)
+ viewHost.addOnAttachStateChangeListener(
+ object : View.OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(p0: View?) {
+ if (rootOverlay == null) {
+ rootView = viewHost.viewRootImpl.view
+ rootOverlay = (rootView!!.overlay as ViewGroupOverlay)
+ }
+ viewHost.removeOnAttachStateChangeListener(this)
}
- viewHost.removeOnAttachStateChangeListener(this)
- }
- override fun onViewDetachedFromWindow(p0: View?) {
+ override fun onViewDetachedFromWindow(p0: View?) {}
}
- })
+ )
return viewHost
}
@@ -643,127 +630,141 @@ class MediaHierarchyManager @Inject constructor(
*
* @param forceNoAnimation optional parameter telling the system not to animate
* @param forceStateUpdate optional parameter telling the system to update transition state
+ * ```
* even if location did not change
+ * ```
*/
private fun updateDesiredLocation(
forceNoAnimation: Boolean = false,
forceStateUpdate: Boolean = false
- ) = traceSection("MediaHierarchyManager#updateDesiredLocation") {
- val desiredLocation = calculateLocation()
- if (desiredLocation != this.desiredLocation || forceStateUpdate) {
- if (this.desiredLocation >= 0 && desiredLocation != this.desiredLocation) {
- // Only update previous location when it actually changes
- previousLocation = this.desiredLocation
- } else if (forceStateUpdate) {
- val onLockscreen = (!bypassController.bypassEnabled &&
- (statusbarState == StatusBarState.KEYGUARD))
- if (desiredLocation == LOCATION_QS && previousLocation == LOCATION_LOCKSCREEN &&
- !onLockscreen) {
- // If media active state changed and the device is now unlocked, update the
- // previous location so we animate between the correct hosts
- previousLocation = LOCATION_QQS
+ ) =
+ traceSection("MediaHierarchyManager#updateDesiredLocation") {
+ val desiredLocation = calculateLocation()
+ if (desiredLocation != this.desiredLocation || forceStateUpdate) {
+ if (this.desiredLocation >= 0 && desiredLocation != this.desiredLocation) {
+ // Only update previous location when it actually changes
+ previousLocation = this.desiredLocation
+ } else if (forceStateUpdate) {
+ val onLockscreen =
+ (!bypassController.bypassEnabled &&
+ (statusbarState == StatusBarState.KEYGUARD))
+ if (
+ desiredLocation == LOCATION_QS &&
+ previousLocation == LOCATION_LOCKSCREEN &&
+ !onLockscreen
+ ) {
+ // If media active state changed and the device is now unlocked, update the
+ // previous location so we animate between the correct hosts
+ previousLocation = LOCATION_QQS
+ }
}
+ val isNewView = this.desiredLocation == -1
+ this.desiredLocation = desiredLocation
+ // Let's perform a transition
+ val animate =
+ !forceNoAnimation && shouldAnimateTransition(desiredLocation, previousLocation)
+ val (animDuration, delay) = getAnimationParams(previousLocation, desiredLocation)
+ val host = getHost(desiredLocation)
+ val willFade = calculateTransformationType() == TRANSFORMATION_TYPE_FADE
+ if (!willFade || isCurrentlyInGuidedTransformation() || !animate) {
+ // if we're fading, we want the desired location / measurement only to change
+ // once fully faded. This is happening in the host attachment
+ mediaCarouselController.onDesiredLocationChanged(
+ desiredLocation,
+ host,
+ animate,
+ animDuration,
+ delay
+ )
+ }
+ performTransitionToNewLocation(isNewView, animate)
}
- val isNewView = this.desiredLocation == -1
- this.desiredLocation = desiredLocation
- // Let's perform a transition
- val animate = !forceNoAnimation &&
- shouldAnimateTransition(desiredLocation, previousLocation)
- val (animDuration, delay) = getAnimationParams(previousLocation, desiredLocation)
- val host = getHost(desiredLocation)
- val willFade = calculateTransformationType() == TRANSFORMATION_TYPE_FADE
- if (!willFade || isCurrentlyInGuidedTransformation() || !animate) {
- // if we're fading, we want the desired location / measurement only to change
- // once fully faded. This is happening in the host attachment
- mediaCarouselController.onDesiredLocationChanged(desiredLocation, host,
- animate, animDuration, delay)
- }
- performTransitionToNewLocation(isNewView, animate)
}
- }
- private fun performTransitionToNewLocation(
- isNewView: Boolean,
- animate: Boolean
- ) = traceSection("MediaHierarchyManager#performTransitionToNewLocation") {
- if (previousLocation < 0 || isNewView) {
- cancelAnimationAndApplyDesiredState()
- return
- }
- val currentHost = getHost(desiredLocation)
- val previousHost = getHost(previousLocation)
- if (currentHost == null || previousHost == null) {
- cancelAnimationAndApplyDesiredState()
- return
- }
- updateTargetState()
- if (isCurrentlyInGuidedTransformation()) {
- applyTargetStateIfNotAnimating()
- } else if (animate) {
- val wasCrossFading = isCrossFadeAnimatorRunning
- val previewsCrossFadeProgress = animationCrossFadeProgress
- animator.cancel()
- if (currentAttachmentLocation != previousLocation ||
- !previousHost.hostView.isAttachedToWindow) {
- // Let's animate to the new position, starting from the current position
- // We also go in here in case the view was detached, since the bounds wouldn't
- // be correct anymore
- animationStartBounds.set(currentBounds)
- animationStartClipping.set(currentClipping)
- } else {
- // otherwise, let's take the freshest state, since the current one could
- // be outdated
- animationStartBounds.set(previousHost.currentBounds)
- animationStartClipping.set(previousHost.currentClipping)
+ private fun performTransitionToNewLocation(isNewView: Boolean, animate: Boolean) =
+ traceSection("MediaHierarchyManager#performTransitionToNewLocation") {
+ if (previousLocation < 0 || isNewView) {
+ cancelAnimationAndApplyDesiredState()
+ return
}
- val transformationType = calculateTransformationType()
- var needsCrossFade = transformationType == TRANSFORMATION_TYPE_FADE
- var crossFadeStartProgress = 0.0f
- // The alpha is only relevant when not cross fading
- var newCrossFadeStartLocation = previousLocation
- if (wasCrossFading) {
- if (currentAttachmentLocation == crossFadeAnimationEndLocation) {
- if (needsCrossFade) {
- // We were previously crossFading and we've already reached
- // the end view, Let's start crossfading from the same position there
- crossFadeStartProgress = 1.0f - previewsCrossFadeProgress
- }
- // Otherwise let's fade in from the current alpha, but not cross fade
+ val currentHost = getHost(desiredLocation)
+ val previousHost = getHost(previousLocation)
+ if (currentHost == null || previousHost == null) {
+ cancelAnimationAndApplyDesiredState()
+ return
+ }
+ updateTargetState()
+ if (isCurrentlyInGuidedTransformation()) {
+ applyTargetStateIfNotAnimating()
+ } else if (animate) {
+ val wasCrossFading = isCrossFadeAnimatorRunning
+ val previewsCrossFadeProgress = animationCrossFadeProgress
+ animator.cancel()
+ if (
+ currentAttachmentLocation != previousLocation ||
+ !previousHost.hostView.isAttachedToWindow
+ ) {
+ // Let's animate to the new position, starting from the current position
+ // We also go in here in case the view was detached, since the bounds wouldn't
+ // be correct anymore
+ animationStartBounds.set(currentBounds)
+ animationStartClipping.set(currentClipping)
} else {
- // We haven't reached the previous location yet, let's still cross fade from
- // where we were.
- newCrossFadeStartLocation = crossFadeAnimationStartLocation
- if (newCrossFadeStartLocation == desiredLocation) {
- // we're crossFading back to where we were, let's start at the end position
- crossFadeStartProgress = 1.0f - previewsCrossFadeProgress
+ // otherwise, let's take the freshest state, since the current one could
+ // be outdated
+ animationStartBounds.set(previousHost.currentBounds)
+ animationStartClipping.set(previousHost.currentClipping)
+ }
+ val transformationType = calculateTransformationType()
+ var needsCrossFade = transformationType == TRANSFORMATION_TYPE_FADE
+ var crossFadeStartProgress = 0.0f
+ // The alpha is only relevant when not cross fading
+ var newCrossFadeStartLocation = previousLocation
+ if (wasCrossFading) {
+ if (currentAttachmentLocation == crossFadeAnimationEndLocation) {
+ if (needsCrossFade) {
+ // We were previously crossFading and we've already reached
+ // the end view, Let's start crossfading from the same position there
+ crossFadeStartProgress = 1.0f - previewsCrossFadeProgress
+ }
+ // Otherwise let's fade in from the current alpha, but not cross fade
} else {
- // Let's start from where we are right now
- crossFadeStartProgress = previewsCrossFadeProgress
- // We need to force cross fading as we haven't reached the end location yet
- needsCrossFade = true
+ // We haven't reached the previous location yet, let's still cross fade from
+ // where we were.
+ newCrossFadeStartLocation = crossFadeAnimationStartLocation
+ if (newCrossFadeStartLocation == desiredLocation) {
+ // we're crossFading back to where we were, let's start at the end
+ // position
+ crossFadeStartProgress = 1.0f - previewsCrossFadeProgress
+ } else {
+ // Let's start from where we are right now
+ crossFadeStartProgress = previewsCrossFadeProgress
+ // We need to force cross fading as we haven't reached the end location
+ // yet
+ needsCrossFade = true
+ }
}
+ } else if (needsCrossFade) {
+ // let's not flicker and start with the same alpha
+ crossFadeStartProgress = (1.0f - carouselAlpha) / 2.0f
}
- } else if (needsCrossFade) {
- // let's not flicker and start with the same alpha
- crossFadeStartProgress = (1.0f - carouselAlpha) / 2.0f
- }
- isCrossFadeAnimatorRunning = needsCrossFade
- crossFadeAnimationStartLocation = newCrossFadeStartLocation
- crossFadeAnimationEndLocation = desiredLocation
- animationStartAlpha = carouselAlpha
- animationStartCrossFadeProgress = crossFadeStartProgress
- adjustAnimatorForTransition(desiredLocation, previousLocation)
- if (!animationPending) {
- rootView?.let {
- // Let's delay the animation start until we finished laying out
- animationPending = true
- it.postOnAnimation(startAnimation)
+ isCrossFadeAnimatorRunning = needsCrossFade
+ crossFadeAnimationStartLocation = newCrossFadeStartLocation
+ crossFadeAnimationEndLocation = desiredLocation
+ animationStartAlpha = carouselAlpha
+ animationStartCrossFadeProgress = crossFadeStartProgress
+ adjustAnimatorForTransition(desiredLocation, previousLocation)
+ if (!animationPending) {
+ rootView?.let {
+ // Let's delay the animation start until we finished laying out
+ animationPending = true
+ it.postOnAnimation(startAnimation)
+ }
}
+ } else {
+ cancelAnimationAndApplyDesiredState()
}
- } else {
- cancelAnimationAndApplyDesiredState()
}
- }
private fun shouldAnimateTransition(
@MediaLocation currentLocation: Int,
@@ -777,23 +778,29 @@ class MediaHierarchyManager @Inject constructor(
}
// This is an invalid transition, and can happen when using the camera gesture from the
// lock screen. Disallow.
- if (previousLocation == LOCATION_LOCKSCREEN &&
- desiredLocation == LOCATION_QQS &&
- statusbarState == StatusBarState.SHADE) {
+ if (
+ previousLocation == LOCATION_LOCKSCREEN &&
+ desiredLocation == LOCATION_QQS &&
+ statusbarState == StatusBarState.SHADE
+ ) {
return false
}
- if (currentLocation == LOCATION_QQS &&
+ if (
+ currentLocation == LOCATION_QQS &&
previousLocation == LOCATION_LOCKSCREEN &&
(statusBarStateController.leaveOpenOnKeyguardHide() ||
- statusbarState == StatusBarState.SHADE_LOCKED)) {
+ statusbarState == StatusBarState.SHADE_LOCKED)
+ ) {
// Usually listening to the isShown is enough to determine this, but there is some
// non-trivial reattaching logic happening that will make the view not-shown earlier
return true
}
- if (statusbarState == StatusBarState.KEYGUARD && (currentLocation == LOCATION_LOCKSCREEN ||
- previousLocation == LOCATION_LOCKSCREEN)) {
+ if (
+ statusbarState == StatusBarState.KEYGUARD &&
+ (currentLocation == LOCATION_LOCKSCREEN || previousLocation == LOCATION_LOCKSCREEN)
+ ) {
// We're always fading from lockscreen to keyguard in situations where the player
// is already fully hidden
return false
@@ -814,8 +821,10 @@ class MediaHierarchyManager @Inject constructor(
var delay = 0L
if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QQS) {
// Going to the full shade, let's adjust the animation duration
- if (statusbarState == StatusBarState.SHADE &&
- keyguardStateController.isKeyguardFadingAway) {
+ if (
+ statusbarState == StatusBarState.SHADE &&
+ keyguardStateController.isKeyguardFadingAway
+ ) {
delay = keyguardStateController.keyguardFadingAwayDelay
}
animDuration = (StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE / 2f).toLong()
@@ -834,14 +843,16 @@ class MediaHierarchyManager @Inject constructor(
}
}
- /**
- * Updates the bounds that the view wants to be in at the end of the animation.
- */
+ /** Updates the bounds that the view wants to be in at the end of the animation. */
private fun updateTargetState() {
var starthost = getHost(previousLocation)
var endHost = getHost(desiredLocation)
- if (isCurrentlyInGuidedTransformation() && !isCurrentlyFading() && starthost != null &&
- endHost != null) {
+ if (
+ isCurrentlyInGuidedTransformation() &&
+ !isCurrentlyFading() &&
+ starthost != null &&
+ endHost != null
+ ) {
val progress = getTransformationProgress()
// If either of the hosts are invisible, let's keep them at the other host location to
// have a nicer disappear animation. Otherwise the currentBounds of the state might
@@ -868,14 +879,15 @@ class MediaHierarchyManager @Inject constructor(
progress: Float,
result: Rect? = null
): Rect {
- val left = MathUtils.lerp(startBounds.left.toFloat(),
- endBounds.left.toFloat(), progress).toInt()
- val top = MathUtils.lerp(startBounds.top.toFloat(),
- endBounds.top.toFloat(), progress).toInt()
- val right = MathUtils.lerp(startBounds.right.toFloat(),
- endBounds.right.toFloat(), progress).toInt()
- val bottom = MathUtils.lerp(startBounds.bottom.toFloat(),
- endBounds.bottom.toFloat(), progress).toInt()
+ val left =
+ MathUtils.lerp(startBounds.left.toFloat(), endBounds.left.toFloat(), progress).toInt()
+ val top =
+ MathUtils.lerp(startBounds.top.toFloat(), endBounds.top.toFloat(), progress).toInt()
+ val right =
+ MathUtils.lerp(startBounds.right.toFloat(), endBounds.right.toFloat(), progress).toInt()
+ val bottom =
+ MathUtils.lerp(startBounds.bottom.toFloat(), endBounds.bottom.toFloat(), progress)
+ .toInt()
val resultBounds = result ?: Rect()
resultBounds.set(left, top, right, bottom)
return resultBounds
@@ -884,17 +896,15 @@ class MediaHierarchyManager @Inject constructor(
/** @return true if this transformation is guided by an external progress like a finger */
fun isCurrentlyInGuidedTransformation(): Boolean {
return hasValidStartAndEndLocations() &&
- getTransformationProgress() >= 0 &&
- areGuidedTransitionHostsVisible()
+ getTransformationProgress() >= 0 &&
+ areGuidedTransitionHostsVisible()
}
private fun hasValidStartAndEndLocations(): Boolean {
return previousLocation != -1 && desiredLocation != -1
}
- /**
- * Calculate the transformation type for the current animation
- */
+ /** Calculate the transformation type for the current animation */
@VisibleForTesting
@TransformationType
fun calculateTransformationType(): Int {
@@ -904,8 +914,10 @@ class MediaHierarchyManager @Inject constructor(
}
return TRANSFORMATION_TYPE_FADE
}
- if (previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QS ||
- previousLocation == LOCATION_QS && desiredLocation == LOCATION_LOCKSCREEN) {
+ if (
+ previousLocation == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QS ||
+ previousLocation == LOCATION_QS && desiredLocation == LOCATION_LOCKSCREEN
+ ) {
// animating between ls and qs should fade, as QS is clipped.
return TRANSFORMATION_TYPE_FADE
}
@@ -918,7 +930,7 @@ class MediaHierarchyManager @Inject constructor(
private fun areGuidedTransitionHostsVisible(): Boolean {
return getHost(previousLocation)?.visible == true &&
- getHost(desiredLocation)?.visible == true
+ getHost(desiredLocation)?.visible == true
}
/**
@@ -966,103 +978,115 @@ class MediaHierarchyManager @Inject constructor(
}
}
- /**
- * Apply the current state to the view, updating it's bounds and desired state
- */
+ /** Apply the current state to the view, updating it's bounds and desired state */
private fun applyState(
bounds: Rect,
alpha: Float,
immediately: Boolean = false,
clipBounds: Rect = EMPTY_RECT
- ) = traceSection("MediaHierarchyManager#applyState") {
- currentBounds.set(bounds)
- currentClipping = clipBounds
- carouselAlpha = if (isCurrentlyFading()) alpha else 1.0f
- val onlyUseEndState = !isCurrentlyInGuidedTransformation() || isCurrentlyFading()
- val startLocation = if (onlyUseEndState) -1 else previousLocation
- val progress = if (onlyUseEndState) 1.0f else getTransformationProgress()
- val endLocation = resolveLocationForFading()
- mediaCarouselController.setCurrentState(startLocation, endLocation, progress, immediately)
- updateHostAttachment()
- if (currentAttachmentLocation == IN_OVERLAY) {
- // Setting the clipping on the hierarchy of `mediaFrame` does not work
- if (!currentClipping.isEmpty) {
- currentBounds.intersect(currentClipping)
- }
- mediaFrame.setLeftTopRightBottom(
+ ) =
+ traceSection("MediaHierarchyManager#applyState") {
+ currentBounds.set(bounds)
+ currentClipping = clipBounds
+ carouselAlpha = if (isCurrentlyFading()) alpha else 1.0f
+ val onlyUseEndState = !isCurrentlyInGuidedTransformation() || isCurrentlyFading()
+ val startLocation = if (onlyUseEndState) -1 else previousLocation
+ val progress = if (onlyUseEndState) 1.0f else getTransformationProgress()
+ val endLocation = resolveLocationForFading()
+ mediaCarouselController.setCurrentState(
+ startLocation,
+ endLocation,
+ progress,
+ immediately
+ )
+ updateHostAttachment()
+ if (currentAttachmentLocation == IN_OVERLAY) {
+ // Setting the clipping on the hierarchy of `mediaFrame` does not work
+ if (!currentClipping.isEmpty) {
+ currentBounds.intersect(currentClipping)
+ }
+ mediaFrame.setLeftTopRightBottom(
currentBounds.left,
currentBounds.top,
currentBounds.right,
- currentBounds.bottom)
+ currentBounds.bottom
+ )
+ }
}
- }
- private fun updateHostAttachment() = traceSection(
- "MediaHierarchyManager#updateHostAttachment"
- ) {
- var newLocation = resolveLocationForFading()
- var canUseOverlay = !isCurrentlyFading()
- if (isCrossFadeAnimatorRunning) {
- if (getHost(newLocation)?.visible == true &&
- getHost(newLocation)?.hostView?.isShown == false &&
- newLocation != desiredLocation) {
- // We're crossfading but the view is already hidden. Let's move to the overlay
- // instead. This happens when animating to the full shade using a button click.
- canUseOverlay = true
+ private fun updateHostAttachment() =
+ traceSection("MediaHierarchyManager#updateHostAttachment") {
+ var newLocation = resolveLocationForFading()
+ var canUseOverlay = !isCurrentlyFading()
+ if (isCrossFadeAnimatorRunning) {
+ if (
+ getHost(newLocation)?.visible == true &&
+ getHost(newLocation)?.hostView?.isShown == false &&
+ newLocation != desiredLocation
+ ) {
+ // We're crossfading but the view is already hidden. Let's move to the overlay
+ // instead. This happens when animating to the full shade using a button click.
+ canUseOverlay = true
+ }
}
- }
- val inOverlay = isTransitionRunning() && rootOverlay != null && canUseOverlay
- newLocation = if (inOverlay) IN_OVERLAY else newLocation
- if (currentAttachmentLocation != newLocation) {
- currentAttachmentLocation = newLocation
+ val inOverlay = isTransitionRunning() && rootOverlay != null && canUseOverlay
+ newLocation = if (inOverlay) IN_OVERLAY else newLocation
+ if (currentAttachmentLocation != newLocation) {
+ currentAttachmentLocation = newLocation
- // Remove the carousel from the old host
- (mediaFrame.parent as ViewGroup?)?.removeView(mediaFrame)
+ // Remove the carousel from the old host
+ (mediaFrame.parent as ViewGroup?)?.removeView(mediaFrame)
- // Add it to the new one
- if (inOverlay) {
- rootOverlay!!.add(mediaFrame)
- } else {
- val targetHost = getHost(newLocation)!!.hostView
- // When adding back to the host, let's make sure to reset the bounds.
- // Usually adding the view will trigger a layout that does this automatically,
- // but we sometimes suppress this.
- targetHost.addView(mediaFrame)
- val left = targetHost.paddingLeft
- val top = targetHost.paddingTop
- mediaFrame.setLeftTopRightBottom(
+ // Add it to the new one
+ if (inOverlay) {
+ rootOverlay!!.add(mediaFrame)
+ } else {
+ val targetHost = getHost(newLocation)!!.hostView
+ // When adding back to the host, let's make sure to reset the bounds.
+ // Usually adding the view will trigger a layout that does this automatically,
+ // but we sometimes suppress this.
+ targetHost.addView(mediaFrame)
+ val left = targetHost.paddingLeft
+ val top = targetHost.paddingTop
+ mediaFrame.setLeftTopRightBottom(
left,
top,
left + currentBounds.width(),
- top + currentBounds.height())
-
- if (mediaFrame.childCount > 0) {
- val child = mediaFrame.getChildAt(0)
- if (mediaFrame.height < child.height) {
- Log.wtf(TAG, "mediaFrame height is too small for child: " +
- "${mediaFrame.height} vs ${child.height}")
+ top + currentBounds.height()
+ )
+
+ if (mediaFrame.childCount > 0) {
+ val child = mediaFrame.getChildAt(0)
+ if (mediaFrame.height < child.height) {
+ Log.wtf(
+ TAG,
+ "mediaFrame height is too small for child: " +
+ "${mediaFrame.height} vs ${child.height}"
+ )
+ }
}
}
- }
- if (isCrossFadeAnimatorRunning) {
- // When cross-fading with an animation, we only notify the media carousel of the
- // location change, once the view is reattached to the new place and not immediately
- // when the desired location changes. This callback will update the measurement
- // of the carousel, only once we've faded out at the old location and then reattach
- // to fade it in at the new location.
- mediaCarouselController.onDesiredLocationChanged(
- newLocation,
- getHost(newLocation),
- animate = false
- )
+ if (isCrossFadeAnimatorRunning) {
+ // When cross-fading with an animation, we only notify the media carousel of the
+ // location change, once the view is reattached to the new place and not
+ // immediately
+ // when the desired location changes. This callback will update the measurement
+ // of the carousel, only once we've faded out at the old location and then
+ // reattach
+ // to fade it in at the new location.
+ mediaCarouselController.onDesiredLocationChanged(
+ newLocation,
+ getHost(newLocation),
+ animate = false
+ )
+ }
}
}
- }
/**
- * Calculate the location when cross fading between locations. While fading out,
- * the content should remain in the previous location, while after the switch it should
- * be at the desired location.
+ * Calculate the location when cross fading between locations. While fading out, the content
+ * should remain in the previous location, while after the switch it should be at the desired
+ * location.
*/
private fun resolveLocationForFading(): Int {
if (isCrossFadeAnimatorRunning) {
@@ -1079,7 +1103,8 @@ class MediaHierarchyManager @Inject constructor(
private fun isTransitionRunning(): Boolean {
return isCurrentlyInGuidedTransformation() && getTransformationProgress() != 1.0f ||
- animator.isRunning || animationPending
+ animator.isRunning ||
+ animationPending
}
@MediaLocation
@@ -1088,31 +1113,39 @@ class MediaHierarchyManager @Inject constructor(
// Keep the current location until we're allowed to again
return desiredLocation
}
- val onLockscreen = (!bypassController.bypassEnabled &&
- (statusbarState == StatusBarState.KEYGUARD))
- val location = when {
- dreamOverlayActive && dreamMediaComplicationActive -> LOCATION_DREAM_OVERLAY
- (qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS
- qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
- !hasActiveMedia -> LOCATION_QS
- onLockscreen && isSplitShadeExpanding() -> LOCATION_QS
- onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS
- onLockscreen && allowMediaPlayerOnLockScreen -> LOCATION_LOCKSCREEN
- else -> LOCATION_QQS
- }
+ val onLockscreen =
+ (!bypassController.bypassEnabled && (statusbarState == StatusBarState.KEYGUARD))
+ val location =
+ when {
+ dreamOverlayActive && dreamMediaComplicationActive -> LOCATION_DREAM_OVERLAY
+ (qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS
+ qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
+ !hasActiveMedia -> LOCATION_QS
+ onLockscreen && isSplitShadeExpanding() -> LOCATION_QS
+ onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS
+ onLockscreen && allowMediaPlayerOnLockScreen -> LOCATION_LOCKSCREEN
+ else -> LOCATION_QQS
+ }
// When we're on lock screen and the player is not active, we should keep it in QS.
// Otherwise it will try to animate a transition that doesn't make sense.
- if (location == LOCATION_LOCKSCREEN && getHost(location)?.visible != true &&
- !statusBarStateController.isDozing) {
+ if (
+ location == LOCATION_LOCKSCREEN &&
+ getHost(location)?.visible != true &&
+ !statusBarStateController.isDozing
+ ) {
return LOCATION_QS
}
- if (location == LOCATION_LOCKSCREEN && desiredLocation == LOCATION_QS &&
- collapsingShadeFromQS) {
+ if (
+ location == LOCATION_LOCKSCREEN &&
+ desiredLocation == LOCATION_QS &&
+ collapsingShadeFromQS
+ ) {
// When collapsing on the lockscreen, we want to remain in QS
return LOCATION_QS
}
- if (location != LOCATION_LOCKSCREEN && desiredLocation == LOCATION_LOCKSCREEN &&
- !fullyAwake) {
+ if (
+ location != LOCATION_LOCKSCREEN && desiredLocation == LOCATION_LOCKSCREEN && !fullyAwake
+ ) {
// When unlocking from dozing / while waking up, the media shouldn't be transitioning
// in an animated way. Let's keep it in the lockscreen until we're fully awake and
// reattach it without an animation
@@ -1129,9 +1162,7 @@ class MediaHierarchyManager @Inject constructor(
return inSplitShade && isTransitioningToFullShade
}
- /**
- * Are we currently transforming to the full shade and already in QQS
- */
+ /** Are we currently transforming to the full shade and already in QQS */
private fun isTransformingToFullShadeAndInQQS(): Boolean {
if (!isTransitioningToFullShade) {
return false
@@ -1143,9 +1174,7 @@ class MediaHierarchyManager @Inject constructor(
return fullShadeTransitionProgress > 0.5f
}
- /**
- * Is the current transformationType fading
- */
+ /** Is the current transformationType fading */
private fun isCurrentlyFading(): Boolean {
if (isSplitShadeExpanding()) {
// Split shade always uses transition instead of fade.
@@ -1157,60 +1186,49 @@ class MediaHierarchyManager @Inject constructor(
return isCrossFadeAnimatorRunning
}
- /**
- * Returns true when the media card could be visible to the user if existed.
- */
+ /** Returns true when the media card could be visible to the user if existed. */
private fun isVisibleToUser(): Boolean {
- return isLockScreenVisibleToUser() || isLockScreenShadeVisibleToUser() ||
- isHomeScreenShadeVisibleToUser()
+ return isLockScreenVisibleToUser() ||
+ isLockScreenShadeVisibleToUser() ||
+ isHomeScreenShadeVisibleToUser()
}
private fun isLockScreenVisibleToUser(): Boolean {
return !statusBarStateController.isDozing &&
- !keyguardViewController.isBouncerShowing &&
- statusBarStateController.state == StatusBarState.KEYGUARD &&
- allowMediaPlayerOnLockScreen &&
- statusBarStateController.isExpanded &&
- !qsExpanded
+ !keyguardViewController.isBouncerShowing &&
+ statusBarStateController.state == StatusBarState.KEYGUARD &&
+ allowMediaPlayerOnLockScreen &&
+ statusBarStateController.isExpanded &&
+ !qsExpanded
}
private fun isLockScreenShadeVisibleToUser(): Boolean {
return !statusBarStateController.isDozing &&
- !keyguardViewController.isBouncerShowing &&
- (statusBarStateController.state == StatusBarState.SHADE_LOCKED ||
- (statusBarStateController.state == StatusBarState.KEYGUARD && qsExpanded))
+ !keyguardViewController.isBouncerShowing &&
+ (statusBarStateController.state == StatusBarState.SHADE_LOCKED ||
+ (statusBarStateController.state == StatusBarState.KEYGUARD && qsExpanded))
}
private fun isHomeScreenShadeVisibleToUser(): Boolean {
return !statusBarStateController.isDozing &&
- statusBarStateController.state == StatusBarState.SHADE &&
- statusBarStateController.isExpanded
+ statusBarStateController.state == StatusBarState.SHADE &&
+ statusBarStateController.isExpanded
}
companion object {
- /**
- * Attached in expanded quick settings
- */
+ /** Attached in expanded quick settings */
const val LOCATION_QS = 0
- /**
- * Attached in the collapsed QS
- */
+ /** Attached in the collapsed QS */
const val LOCATION_QQS = 1
- /**
- * Attached on the lock screen
- */
+ /** Attached on the lock screen */
const val LOCATION_LOCKSCREEN = 2
- /**
- * Attached on the dream overlay
- */
+ /** Attached on the dream overlay */
const val LOCATION_DREAM_OVERLAY = 3
- /**
- * Attached at the root of the hierarchy in an overlay
- */
+ /** Attached at the root of the hierarchy in an overlay */
const val IN_OVERLAY = -1000
/**
@@ -1226,18 +1244,29 @@ class MediaHierarchyManager @Inject constructor(
const val TRANSFORMATION_TYPE_FADE = 1
}
}
+
private val EMPTY_RECT = Rect()
-@IntDef(prefix = ["TRANSFORMATION_TYPE_"], value = [
- MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION,
- MediaHierarchyManager.TRANSFORMATION_TYPE_FADE])
+@IntDef(
+ prefix = ["TRANSFORMATION_TYPE_"],
+ value =
+ [
+ MediaHierarchyManager.TRANSFORMATION_TYPE_TRANSITION,
+ MediaHierarchyManager.TRANSFORMATION_TYPE_FADE
+ ]
+)
@Retention(AnnotationRetention.SOURCE)
private annotation class TransformationType
-@IntDef(prefix = ["LOCATION_"], value = [
- MediaHierarchyManager.LOCATION_QS,
- MediaHierarchyManager.LOCATION_QQS,
- MediaHierarchyManager.LOCATION_LOCKSCREEN,
- MediaHierarchyManager.LOCATION_DREAM_OVERLAY])
+@IntDef(
+ prefix = ["LOCATION_"],
+ value =
+ [
+ MediaHierarchyManager.LOCATION_QS,
+ MediaHierarchyManager.LOCATION_QQS,
+ MediaHierarchyManager.LOCATION_LOCKSCREEN,
+ MediaHierarchyManager.LOCATION_DREAM_OVERLAY
+ ]
+)
@Retention(AnnotationRetention.SOURCE)
annotation class MediaLocation
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
index 87b87fd38e04..455b7de3dc0c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHost.kt
@@ -30,7 +30,8 @@ import com.android.systemui.util.animation.UniqueObjectHostView
import java.util.Objects
import javax.inject.Inject
-class MediaHost constructor(
+class MediaHost
+constructor(
private val state: MediaHostStateHolder,
private val mediaHierarchyManager: MediaHierarchyManager,
private val mediaDataManager: MediaDataManager,
@@ -45,14 +46,10 @@ class MediaHost constructor(
private var inited: Boolean = false
- /**
- * Are we listening to media data changes?
- */
+ /** 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
- */
+ /** Get the current bounds on the screen. This makes sure the state is fresh and up to date */
val currentBounds: Rect = Rect()
get() {
hostView.getLocationOnScreen(tmpLocationOnScreen)
@@ -81,38 +78,39 @@ class MediaHost constructor(
*/
val currentClipping = Rect()
- private val listener = object : MediaDataManager.Listener {
- override fun onMediaDataLoaded(
- key: String,
- oldKey: String?,
- data: MediaData,
- immediately: Boolean,
- receivedSmartspaceCardLatency: Int,
- isSsReactivated: Boolean
- ) {
- if (immediately) {
- updateViewVisibility()
+ private val listener =
+ object : MediaDataManager.Listener {
+ override fun onMediaDataLoaded(
+ key: String,
+ oldKey: String?,
+ data: MediaData,
+ immediately: Boolean,
+ receivedSmartspaceCardLatency: Int,
+ isSsReactivated: Boolean
+ ) {
+ if (immediately) {
+ updateViewVisibility()
+ }
}
- }
-
- override fun onSmartspaceMediaDataLoaded(
- key: String,
- data: SmartspaceMediaData,
- shouldPrioritize: Boolean
- ) {
- updateViewVisibility()
- }
- override fun onMediaDataRemoved(key: String) {
- updateViewVisibility()
- }
+ override fun onSmartspaceMediaDataLoaded(
+ key: String,
+ data: SmartspaceMediaData,
+ shouldPrioritize: Boolean
+ ) {
+ updateViewVisibility()
+ }
- override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
- if (immediately) {
+ override fun onMediaDataRemoved(key: String) {
updateViewVisibility()
}
+
+ override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
+ if (immediately) {
+ updateViewVisibility()
+ }
+ }
}
- }
fun addVisibilityChangeListener(listener: (Boolean) -> Unit) {
visibleChangedListeners.add(listener)
@@ -123,12 +121,14 @@ class MediaHost constructor(
}
/**
- * Initialize this MediaObject and create a host view.
- * All state should already be set on this host before calling this method in order to avoid
- * unnecessary state changes which lead to remeasurings later on.
+ * Initialize this MediaObject and create a host view. All state should already be set on this
+ * host before calling this method in order to avoid unnecessary state changes which lead to
+ * remeasurings later on.
*
* @param location the location this host name has. Used to identify the host during
+ * ```
* transitions.
+ * ```
*/
fun init(@MediaLocation location: Int) {
if (inited) {
@@ -141,36 +141,42 @@ class MediaHost constructor(
// 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?) {
- setListeningToMediaData(true)
- updateViewVisibility()
- }
+ hostView.addOnAttachStateChangeListener(
+ object : OnAttachStateChangeListener {
+ override fun onViewAttachedToWindow(v: View?) {
+ setListeningToMediaData(true)
+ updateViewVisibility()
+ }
- override fun onViewDetachedFromWindow(v: View?) {
- setListeningToMediaData(false)
+ override fun onViewDetachedFromWindow(v: View?) {
+ setListeningToMediaData(false)
+ }
}
- })
+ )
// Listen to measurement updates and update our state with it
- hostView.measurementManager = object : UniqueObjectHostView.MeasurementManager {
- override fun onMeasure(input: MeasurementInput): MeasurementOutput {
- // Modify the measurement to exactly match the dimensions
- if (View.MeasureSpec.getMode(input.widthMeasureSpec) == View.MeasureSpec.AT_MOST) {
- input.widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(
- View.MeasureSpec.getSize(input.widthMeasureSpec),
- View.MeasureSpec.EXACTLY)
+ hostView.measurementManager =
+ object : UniqueObjectHostView.MeasurementManager {
+ override fun onMeasure(input: MeasurementInput): MeasurementOutput {
+ // Modify the measurement to exactly match the dimensions
+ if (
+ View.MeasureSpec.getMode(input.widthMeasureSpec) == View.MeasureSpec.AT_MOST
+ ) {
+ input.widthMeasureSpec =
+ View.MeasureSpec.makeMeasureSpec(
+ View.MeasureSpec.getSize(input.widthMeasureSpec),
+ View.MeasureSpec.EXACTLY
+ )
+ }
+ // This will trigger a state change that ensures that we now have a state
+ // available
+ state.measurementInput = input
+ return mediaHostStatesManager.updateCarouselDimensions(location, state)
}
- // This will trigger a state change that ensures that we now have a state available
- state.measurementInput = input
- return mediaHostStatesManager.updateCarouselDimensions(location, state)
}
- }
// Whenever the state changes, let our state manager know
- state.changedListener = {
- mediaHostStatesManager.updateHostState(location, state)
- }
+ state.changedListener = { mediaHostStatesManager.updateHostState(location, state) }
updateViewVisibility()
}
@@ -191,17 +197,16 @@ class MediaHost constructor(
* the visibility has changed
*/
fun updateViewVisibility() {
- state.visible = if (showsOnlyActiveMedia) {
- mediaDataManager.hasActiveMediaOrRecommendation()
- } else {
- mediaDataManager.hasAnyMediaOrRecommendation()
- }
+ state.visible =
+ if (showsOnlyActiveMedia) {
+ mediaDataManager.hasActiveMediaOrRecommendation()
+ } else {
+ mediaDataManager.hasAnyMediaOrRecommendation()
+ }
val newVisibility = if (visible) View.VISIBLE else View.GONE
if (newVisibility != hostView.visibility) {
hostView.visibility = newVisibility
- visibleChangedListeners.forEach {
- it.invoke(visible)
- }
+ visibleChangedListeners.forEach { it.invoke(visible) }
}
}
@@ -269,14 +274,10 @@ class MediaHost constructor(
private var lastDisappearHash = disappearParameters.hashCode()
- /**
- * A listener for all changes. This won't be copied over when invoking [copy]
- */
+ /** A listener for all changes. This won't be copied over when invoking [copy] */
var changedListener: (() -> Unit)? = null
- /**
- * Get a copy of this state. This won't copy any listeners it may have set
- */
+ /** Get a copy of this state. This won't copy any listeners it may have set */
override fun copy(): MediaHostState {
val mediaHostState = MediaHostStateHolder()
mediaHostState.expansion = expansion
@@ -331,15 +332,13 @@ class MediaHost constructor(
}
/**
- * A description of a media host state that describes the behavior whenever the media carousel
- * is hosted. The HostState notifies the media players of changes to their properties, who
- * in turn will create view states from it.
- * When adding a new property to this, make sure to update the listener and notify them
- * about the changes.
- * In case you need to have a different rendering based on the state, you can add a new
- * constraintState to the [MediaViewController]. Otherwise, similar host states will resolve
- * to the same viewstate, a behavior that is described in [CacheKey]. Make sure to only update
- * that key if the underlying view needs to have a different measurement.
+ * A description of a media host state that describes the behavior whenever the media carousel is
+ * hosted. The HostState notifies the media players of changes to their properties, who in turn will
+ * create view states from it. When adding a new property to this, make sure to update the listener
+ * and notify them about the changes. In case you need to have a different rendering based on the
+ * state, you can add a new constraintState to the [MediaViewController]. Otherwise, similar host
+ * states will resolve to the same viewstate, a behavior that is described in [CacheKey]. Make sure
+ * to only update that key if the underlying view needs to have a different measurement.
*/
interface MediaHostState {
@@ -349,46 +348,36 @@ interface MediaHostState {
}
/**
- * The last measurement input that this state was measured with. Infers width and height of
- * the players.
+ * The last measurement input that this state was measured with. Infers width and height of the
+ * players.
*/
var measurementInput: MeasurementInput?
/**
- * The expansion of the player, [COLLAPSED] for fully collapsed (up to 3 actions),
- * [EXPANDED] for fully expanded (up to 5 actions).
+ * The expansion of the player, [COLLAPSED] for fully collapsed (up to 3 actions), [EXPANDED]
+ * for fully expanded (up to 5 actions).
*/
var expansion: Float
- /**
- * Fraction of the height animation.
- */
+ /** Fraction of the height animation. */
var squishFraction: Float
- /**
- * Is this host only showing active media or is it showing all of them including resumption?
- */
+ /** Is this host only showing active media or is it showing all of them including resumption? */
var showsOnlyActiveMedia: Boolean
- /**
- * If the view should be VISIBLE or GONE.
- */
+ /** If the view should be VISIBLE or GONE. */
val visible: Boolean
- /**
- * Does this host need any falsing protection?
- */
+ /** Does this host need any falsing protection? */
var falsingProtectionNeeded: Boolean
/**
* The parameters how the view disappears from this location when going to a host that's not
- * visible. If modified, make sure to set this value again on the host to ensure the values
- * are propagated
+ * visible. If modified, make sure to set this value again on the host to ensure the values are
+ * propagated
*/
var disappearParameters: DisappearParameters
- /**
- * Get a copy of this view state, deepcopying all appropriate members
- */
+ /** Get a copy of this view state, deepcopying all appropriate members */
fun copy(): MediaHostState
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHostStatesManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHostStatesManager.kt
index 72899e59579b..ae3ce333d41d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHostStatesManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHostStatesManager.kt
@@ -38,85 +38,76 @@ class MediaHostStatesManager @Inject constructor() {
*/
val carouselSizes: MutableMap<Int, MeasurementOutput> = mutableMapOf()
- /**
- * A map with all media states of all locations.
- */
+ /** A map with all media states of all locations. */
val mediaHostStates: MutableMap<Int, MediaHostState> = mutableMapOf()
/**
- * Notify that a media state for a given location has changed. Should only be called from
- * Media hosts themselves.
+ * Notify that a media state for a given location has changed. Should only be called from Media
+ * hosts themselves.
*/
- fun updateHostState(
- @MediaLocation location: Int,
- hostState: MediaHostState
- ) = traceSection("MediaHostStatesManager#updateHostState") {
- val currentState = mediaHostStates.get(location)
- if (!hostState.equals(currentState)) {
- val newState = hostState.copy()
- mediaHostStates.put(location, newState)
- updateCarouselDimensions(location, hostState)
- // First update all the controllers to ensure they get the chance to measure
- for (controller in controllers) {
- controller.stateCallback.onHostStateChanged(location, newState)
- }
+ fun updateHostState(@MediaLocation location: Int, hostState: MediaHostState) =
+ traceSection("MediaHostStatesManager#updateHostState") {
+ val currentState = mediaHostStates.get(location)
+ if (!hostState.equals(currentState)) {
+ val newState = hostState.copy()
+ mediaHostStates.put(location, newState)
+ updateCarouselDimensions(location, hostState)
+ // First update all the controllers to ensure they get the chance to measure
+ for (controller in controllers) {
+ controller.stateCallback.onHostStateChanged(location, newState)
+ }
- // Then update all other callbacks which may depend on the controllers above
- for (callback in callbacks) {
- callback.onHostStateChanged(location, newState)
+ // Then update all other callbacks which may depend on the controllers above
+ for (callback in callbacks) {
+ callback.onHostStateChanged(location, newState)
+ }
}
}
- }
/**
- * Get the dimensions of all players combined, which determines the overall height of the
- * media carousel and the media hosts.
+ * Get the dimensions of all players combined, which determines the overall height of the media
+ * carousel and the media hosts.
*/
fun updateCarouselDimensions(
@MediaLocation location: Int,
hostState: MediaHostState
- ): MeasurementOutput = traceSection("MediaHostStatesManager#updateCarouselDimensions") {
- val result = MeasurementOutput(0, 0)
- for (controller in controllers) {
- val measurement = controller.getMeasurementsForState(hostState)
- measurement?.let {
- if (it.measuredHeight > result.measuredHeight) {
- result.measuredHeight = it.measuredHeight
- }
- if (it.measuredWidth > result.measuredWidth) {
- result.measuredWidth = it.measuredWidth
+ ): MeasurementOutput =
+ traceSection("MediaHostStatesManager#updateCarouselDimensions") {
+ val result = MeasurementOutput(0, 0)
+ for (controller in controllers) {
+ val measurement = controller.getMeasurementsForState(hostState)
+ measurement?.let {
+ if (it.measuredHeight > result.measuredHeight) {
+ result.measuredHeight = it.measuredHeight
+ }
+ if (it.measuredWidth > result.measuredWidth) {
+ result.measuredWidth = it.measuredWidth
+ }
}
}
+ carouselSizes[location] = result
+ return result
}
- carouselSizes[location] = result
- return result
- }
- /**
- * Add a callback to be called when a MediaState has updated
- */
+ /** Add a callback to be called when a MediaState has updated */
fun addCallback(callback: Callback) {
callbacks.add(callback)
}
- /**
- * Remove a callback that listens to media states
- */
+ /** Remove a callback that listens to media states */
fun removeCallback(callback: Callback) {
callbacks.remove(callback)
}
/**
- * Register a controller that listens to media states and is used to determine the size of
- * the media carousel
+ * Register a controller that listens to media states and is used to determine the size of the
+ * media carousel
*/
fun addController(controller: MediaViewController) {
controllers.add(controller)
}
- /**
- * Notify the manager about the removal of a controller.
- */
+ /** Notify the manager about the removal of a controller. */
fun removeController(controller: MediaViewController) {
controllers.remove(controller)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaScrollView.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaScrollView.kt
index 268961ca56aa..0e0746590776 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaScrollView.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaScrollView.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.media.controls.ui
import android.content.Context
@@ -11,14 +27,13 @@ import com.android.systemui.Gefingerpoken
import com.android.wm.shell.animation.physicsAnimator
/**
- * A ScrollView used in Media that doesn't limit itself to the childs bounds. This is useful
- * when only measuring children but not the parent, when trying to apply a new scroll position
+ * A ScrollView used in Media that doesn't limit itself to the childs bounds. This is useful when
+ * only measuring children but not the parent, when trying to apply a new scroll position
*/
-class MediaScrollView @JvmOverloads constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0
-) : HorizontalScrollView(context, attrs, defStyleAttr) {
+class MediaScrollView
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
+ HorizontalScrollView(context, attrs, defStyleAttr) {
lateinit var contentContainer: ViewGroup
private set
@@ -33,35 +48,33 @@ class MediaScrollView @JvmOverloads constructor(
* Get the current content translation. This is usually the normal translationX of the content,
* but when animating, it might differ
*/
- fun getContentTranslation() = if (contentContainer.physicsAnimator.isRunning()) {
- animationTargetX
- } else {
- contentContainer.translationX
- }
+ fun getContentTranslation() =
+ if (contentContainer.physicsAnimator.isRunning()) {
+ animationTargetX
+ } else {
+ contentContainer.translationX
+ }
/**
* Convert between the absolute (left-to-right) and relative (start-to-end) scrollX of the media
- * carousel. The player indices are always relative (start-to-end) and the scrollView.scrollX
- * is always absolute. This function is its own inverse.
+ * carousel. The player indices are always relative (start-to-end) and the scrollView.scrollX is
+ * always absolute. This function is its own inverse.
*/
- private fun transformScrollX(scrollX: Int): Int = if (isLayoutRtl) {
- contentContainer.width - width - scrollX
- } else {
- scrollX
- }
+ private fun transformScrollX(scrollX: Int): Int =
+ if (isLayoutRtl) {
+ contentContainer.width - width - scrollX
+ } else {
+ scrollX
+ }
- /**
- * Get the layoutDirection-relative (start-to-end) scroll X position of the carousel.
- */
+ /** Get the layoutDirection-relative (start-to-end) scroll X position of the carousel. */
var relativeScrollX: Int
get() = transformScrollX(scrollX)
set(value) {
scrollX = transformScrollX(value)
}
- /**
- * Allow all scrolls to go through, use base implementation
- */
+ /** Allow all scrolls to go through, use base implementation */
override fun scrollTo(x: Int, y: Int) {
if (mScrollX != x || mScrollY != y) {
val oldX: Int = mScrollX
@@ -78,17 +91,13 @@ class MediaScrollView @JvmOverloads constructor(
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
var intercept = false
- touchListener?.let {
- intercept = it.onInterceptTouchEvent(ev)
- }
+ touchListener?.let { intercept = it.onInterceptTouchEvent(ev) }
return super.onInterceptTouchEvent(ev) || intercept
}
override fun onTouchEvent(ev: MotionEvent?): Boolean {
var touch = false
- touchListener?.let {
- touch = it.onTouchEvent(ev)
- }
+ touchListener?.let { touch = it.onTouchEvent(ev) }
return super.onTouchEvent(ev) || touch
}
@@ -112,19 +121,25 @@ class MediaScrollView @JvmOverloads constructor(
// When we're dismissing we ignore all the scrolling
return false
}
- return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
- scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent)
+ return super.overScrollBy(
+ deltaX,
+ deltaY,
+ scrollX,
+ scrollY,
+ scrollRangeX,
+ scrollRangeY,
+ maxOverScrollX,
+ maxOverScrollY,
+ isTouchEvent
+ )
}
- /**
- * Cancel the current touch event going on.
- */
+ /** Cancel the current touch event going on. */
fun cancelCurrentScroll() {
val now = SystemClock.uptimeMillis()
- val event = MotionEvent.obtain(now, now,
- MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0)
+ val event = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0)
event.source = InputDevice.SOURCE_TOUCHSCREEN
super.onTouchEvent(event)
event.recycle()
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
index 0a13d44f1b26..4bf3031c02b4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
@@ -42,7 +42,9 @@ import javax.inject.Inject
* A class responsible for controlling a single instance of a media player handling interactions
* with the view instance and keeping the media view states up to date.
*/
-class MediaViewController @Inject constructor(
+class MediaViewController
+@Inject
+constructor(
private val context: Context,
private val configurationController: ConfigurationController,
private val mediaHostStatesManager: MediaHostStatesManager,
@@ -50,17 +52,18 @@ class MediaViewController @Inject constructor(
) {
/**
- * Indicating that the media view controller is for a notification-based player,
- * session-based player, or recommendation
+ * Indicating that the media view controller is for a notification-based player, session-based
+ * player, or recommendation
*/
enum class TYPE {
- PLAYER, RECOMMENDATION
+ PLAYER,
+ RECOMMENDATION
}
companion object {
- @JvmField
- val GUTS_ANIMATION_DURATION = 500L
- val controlIds = setOf(
+ @JvmField val GUTS_ANIMATION_DURATION = 500L
+ val controlIds =
+ setOf(
R.id.media_progress_bar,
R.id.actionNext,
R.id.actionPrev,
@@ -71,22 +74,20 @@ class MediaViewController @Inject constructor(
R.id.action4,
R.id.media_scrubbing_elapsed_time,
R.id.media_scrubbing_total_time
- )
+ )
- val detailIds = setOf(
+ val detailIds =
+ setOf(
R.id.header_title,
R.id.header_artist,
R.id.actionPlayPause,
- )
+ )
}
- /**
- * A listener when the current dimensions of the player change
- */
+ /** A listener when the current dimensions of the player change */
lateinit var sizeChangedListener: () -> Unit
private var firstRefresh: Boolean = true
- @VisibleForTesting
- private var transitionLayout: TransitionLayout? = null
+ @VisibleForTesting private var transitionLayout: TransitionLayout? = null
private val layoutController = TransitionLayoutController()
private var animationDelay: Long = 0
private var animationDuration: Long = 0
@@ -94,116 +95,98 @@ class MediaViewController @Inject constructor(
private val measurement = MeasurementOutput(0, 0)
private var type: TYPE = TYPE.PLAYER
- /**
- * A map containing all viewStates for all locations of this mediaState
- */
+ /** A map containing all viewStates for all locations of this mediaState */
private val viewStates: MutableMap<CacheKey, TransitionViewState?> = mutableMapOf()
/**
* The ending location of the view where it ends when all animations and transitions have
* finished
*/
- @MediaLocation
- var currentEndLocation: Int = -1
+ @MediaLocation var currentEndLocation: Int = -1
- /**
- * The starting location of the view where it starts for all animations and transitions
- */
- @MediaLocation
- private var currentStartLocation: Int = -1
+ /** The starting location of the view where it starts for all animations and transitions */
+ @MediaLocation private var currentStartLocation: Int = -1
- /**
- * The progress of the transition or 1.0 if there is no transition happening
- */
+ /** The progress of the transition or 1.0 if there is no transition happening */
private var currentTransitionProgress: Float = 1.0f
- /**
- * A temporary state used to store intermediate measurements.
- */
+ /** A temporary state used to store intermediate measurements. */
private val tmpState = TransitionViewState()
- /**
- * A temporary state used to store intermediate measurements.
- */
+ /** A temporary state used to store intermediate measurements. */
private val tmpState2 = TransitionViewState()
- /**
- * A temporary state used to store intermediate measurements.
- */
+ /** A temporary state used to store intermediate measurements. */
private val tmpState3 = TransitionViewState()
- /**
- * A temporary cache key to be used to look up cache entries
- */
+ /** A temporary cache key to be used to look up cache entries */
private val tmpKey = CacheKey()
/**
- * The current width of the player. This might not factor in case the player is animating
- * to the current state, but represents the end state
+ * The current width of the player. This might not factor in case the player is animating to the
+ * current state, but represents the end state
*/
var currentWidth: Int = 0
/**
- * The current height of the player. This might not factor in case the player is animating
- * to the current state, but represents the end state
+ * The current height of the player. This might not factor in case the player is animating to
+ * the current state, but represents the end state
*/
var currentHeight: Int = 0
- /**
- * Get the translationX of the layout
- */
+ /** Get the translationX of the layout */
var translationX: Float = 0.0f
private set
get() {
return transitionLayout?.translationX ?: 0.0f
}
- /**
- * Get the translationY of the layout
- */
+ /** Get the translationY of the layout */
var translationY: Float = 0.0f
private set
get() {
return transitionLayout?.translationY ?: 0.0f
}
- /**
- * A callback for RTL config changes
- */
- private val configurationListener = object : ConfigurationController.ConfigurationListener {
- override fun onConfigChanged(newConfig: Configuration?) {
- // Because the TransitionLayout is not always attached (and calculates/caches layout
- // results regardless of attach state), we have to force the layoutDirection of the view
- // to the correct value for the user's current locale to ensure correct recalculation
- // when/after calling refreshState()
- newConfig?.apply {
- if (transitionLayout?.rawLayoutDirection != layoutDirection) {
- transitionLayout?.layoutDirection = layoutDirection
- refreshState()
+ /** A callback for RTL config changes */
+ private val configurationListener =
+ object : ConfigurationController.ConfigurationListener {
+ override fun onConfigChanged(newConfig: Configuration?) {
+ // Because the TransitionLayout is not always attached (and calculates/caches layout
+ // results regardless of attach state), we have to force the layoutDirection of the
+ // view
+ // to the correct value for the user's current locale to ensure correct
+ // recalculation
+ // when/after calling refreshState()
+ newConfig?.apply {
+ if (transitionLayout?.rawLayoutDirection != layoutDirection) {
+ transitionLayout?.layoutDirection = layoutDirection
+ refreshState()
+ }
}
}
}
- }
- /**
- * A callback for media state changes
- */
- val stateCallback = object : MediaHostStatesManager.Callback {
- override fun onHostStateChanged(
- @MediaLocation location: Int,
- mediaHostState: MediaHostState
- ) {
- if (location == currentEndLocation || location == currentStartLocation) {
- setCurrentState(currentStartLocation,
+ /** A callback for media state changes */
+ val stateCallback =
+ object : MediaHostStatesManager.Callback {
+ override fun onHostStateChanged(
+ @MediaLocation location: Int,
+ mediaHostState: MediaHostState
+ ) {
+ if (location == currentEndLocation || location == currentStartLocation) {
+ setCurrentState(
+ currentStartLocation,
currentEndLocation,
currentTransitionProgress,
- applyImmediately = false)
+ applyImmediately = false
+ )
+ }
}
}
- }
/**
- * The expanded constraint set used to render a expanded player. If it is modified, make sure
- * to call [refreshState]
+ * The expanded constraint set used to render a expanded player. If it is modified, make sure to
+ * call [refreshState]
*/
val collapsedLayout = ConstraintSet()
@@ -213,9 +196,7 @@ class MediaViewController @Inject constructor(
*/
val expandedLayout = ConstraintSet()
- /**
- * Whether the guts are visible for the associated player.
- */
+ /** Whether the guts are visible for the associated player. */
var isGutsVisible = false
private set
@@ -237,17 +218,17 @@ class MediaViewController @Inject constructor(
configurationController.removeCallback(configurationListener)
}
- /**
- * Show guts with an animated transition.
- */
+ /** Show guts with an animated transition. */
fun openGuts() {
if (isGutsVisible) return
isGutsVisible = true
animatePendingStateChange(GUTS_ANIMATION_DURATION, 0L)
- setCurrentState(currentStartLocation,
- currentEndLocation,
- currentTransitionProgress,
- applyImmediately = false)
+ setCurrentState(
+ currentStartLocation,
+ currentEndLocation,
+ currentTransitionProgress,
+ applyImmediately = false
+ )
}
/**
@@ -262,10 +243,12 @@ class MediaViewController @Inject constructor(
if (!immediate) {
animatePendingStateChange(GUTS_ANIMATION_DURATION, 0L)
}
- setCurrentState(currentStartLocation,
- currentEndLocation,
- currentTransitionProgress,
- applyImmediately = immediate)
+ setCurrentState(
+ currentStartLocation,
+ currentEndLocation,
+ currentTransitionProgress,
+ applyImmediately = immediate
+ )
}
private fun ensureAllMeasurements() {
@@ -275,21 +258,20 @@ class MediaViewController @Inject constructor(
}
}
- /**
- * Get the constraintSet for a given expansion
- */
+ /** Get the constraintSet for a given expansion */
private fun constraintSetForExpansion(expansion: Float): ConstraintSet =
- if (expansion > 0) expandedLayout else collapsedLayout
+ if (expansion > 0) expandedLayout else collapsedLayout
/**
* Set the views to be showing/hidden based on the [isGutsVisible] for a given
* [TransitionViewState].
*/
private fun setGutsViewState(viewState: TransitionViewState) {
- val controlsIds = when (type) {
- TYPE.PLAYER -> MediaViewHolder.controlsIds
- TYPE.RECOMMENDATION -> RecommendationViewHolder.controlsIds
- }
+ val controlsIds =
+ when (type) {
+ TYPE.PLAYER -> MediaViewHolder.controlsIds
+ TYPE.RECOMMENDATION -> RecommendationViewHolder.controlsIds
+ }
val gutsIds = GutsViewHolder.ids
controlsIds.forEach { id ->
viewState.widgetStates.get(id)?.let { state ->
@@ -307,9 +289,7 @@ class MediaViewController @Inject constructor(
}
}
- /**
- * Apply squishFraction to a copy of viewState such that the cached version is untouched.
- */
+ /** Apply squishFraction to a copy of viewState such that the cached version is untouched. */
internal fun squishViewState(
viewState: TransitionViewState,
squishFraction: Float
@@ -347,8 +327,8 @@ class MediaViewController @Inject constructor(
* Obtain a new viewState for a given media state. This usually returns a cached state, but if
* it's not available, it will recreate one by measuring, which may be expensive.
*/
- @VisibleForTesting
- fun obtainViewState(state: MediaHostState?): TransitionViewState? {
+ @VisibleForTesting
+ fun obtainViewState(state: MediaHostState?): TransitionViewState? {
if (state == null || state.measurementInput == null) {
return null
}
@@ -371,10 +351,12 @@ class MediaViewController @Inject constructor(
}
// Let's create a new measurement
if (state.expansion == 0.0f || state.expansion == 1.0f) {
- result = transitionLayout!!.calculateViewState(
+ result =
+ transitionLayout!!.calculateViewState(
state.measurementInput!!,
constraintSetForExpansion(state.expansion),
- TransitionViewState())
+ TransitionViewState()
+ )
setGutsViewState(result)
// We don't want to cache interpolated or null states as this could quickly fill up
@@ -390,10 +372,8 @@ class MediaViewController @Inject constructor(
val startViewState = obtainViewState(startState) as TransitionViewState
val endState = state.copy().also { it.expansion = 1.0f }
val endViewState = obtainViewState(endState) as TransitionViewState
- result = layoutController.getInterpolatedState(
- startViewState,
- endViewState,
- state.expansion)
+ result =
+ layoutController.getInterpolatedState(startViewState, endViewState, state.expansion)
}
if (state.squishFraction <= 1f) {
return squishViewState(result, state.squishFraction)
@@ -401,11 +381,7 @@ class MediaViewController @Inject constructor(
return result
}
- private fun getKey(
- state: MediaHostState,
- guts: Boolean,
- result: CacheKey
- ): CacheKey {
+ private fun getKey(state: MediaHostState, guts: Boolean, result: CacheKey): CacheKey {
result.apply {
heightMeasureSpec = state.measurementInput?.heightMeasureSpec ?: 0
widthMeasureSpec = state.measurementInput?.widthMeasureSpec ?: 0
@@ -416,41 +392,39 @@ class MediaViewController @Inject constructor(
}
/**
- * Attach a view to this controller. This may perform measurements if it's not available yet
- * and should therefore be done carefully.
+ * Attach a view to this controller. This may perform measurements if it's not available yet and
+ * should therefore be done carefully.
*/
- fun attach(
- transitionLayout: TransitionLayout,
- type: TYPE
- ) = traceSection("MediaViewController#attach") {
- updateMediaViewControllerType(type)
- logger.logMediaLocation("attach $type", currentStartLocation, currentEndLocation)
- this.transitionLayout = transitionLayout
- layoutController.attach(transitionLayout)
- if (currentEndLocation == -1) {
- return
- }
- // Set the previously set state immediately to the view, now that it's finally attached
- setCurrentState(
+ fun attach(transitionLayout: TransitionLayout, type: TYPE) =
+ traceSection("MediaViewController#attach") {
+ updateMediaViewControllerType(type)
+ logger.logMediaLocation("attach $type", currentStartLocation, currentEndLocation)
+ this.transitionLayout = transitionLayout
+ layoutController.attach(transitionLayout)
+ if (currentEndLocation == -1) {
+ return
+ }
+ // Set the previously set state immediately to the view, now that it's finally attached
+ setCurrentState(
startLocation = currentStartLocation,
endLocation = currentEndLocation,
transitionProgress = currentTransitionProgress,
- applyImmediately = true)
- }
+ applyImmediately = true
+ )
+ }
/**
- * Obtain a measurement for a given location. This makes sure that the state is up to date
- * and all widgets know their location. Calling this method may create a measurement if we
- * don't have a cached value available already.
+ * Obtain a measurement for a given location. This makes sure that the state is up to date and
+ * all widgets know their location. Calling this method may create a measurement if we don't
+ * have a cached value available already.
*/
- fun getMeasurementsForState(
- hostState: MediaHostState
- ): MeasurementOutput? = traceSection("MediaViewController#getMeasurementsForState") {
- val viewState = obtainViewState(hostState) ?: return null
- measurement.measuredWidth = viewState.width
- measurement.measuredHeight = viewState.height
- return measurement
- }
+ fun getMeasurementsForState(hostState: MediaHostState): MeasurementOutput? =
+ traceSection("MediaViewController#getMeasurementsForState") {
+ val viewState = obtainViewState(hostState) ?: return null
+ measurement.measuredWidth = viewState.width
+ measurement.measuredHeight = viewState.height
+ return measurement
+ }
/**
* Set a new state for the controlled view which can be an interpolation between multiple
@@ -461,67 +435,85 @@ class MediaViewController @Inject constructor(
@MediaLocation endLocation: Int,
transitionProgress: Float,
applyImmediately: Boolean
- ) = traceSection("MediaViewController#setCurrentState") {
- currentEndLocation = endLocation
- currentStartLocation = startLocation
- currentTransitionProgress = transitionProgress
- logger.logMediaLocation("setCurrentState", startLocation, endLocation)
-
- val shouldAnimate = animateNextStateChange && !applyImmediately
-
- val endHostState = mediaHostStatesManager.mediaHostStates[endLocation] ?: return
- val startHostState = mediaHostStatesManager.mediaHostStates[startLocation]
-
- // Obtain the view state that we'd want to be at the end
- // The view might not be bound yet or has never been measured and in that case will be
- // reset once the state is fully available
- var endViewState = obtainViewState(endHostState) ?: return
- endViewState = updateViewStateToCarouselSize(endViewState, endLocation, tmpState2)!!
- layoutController.setMeasureState(endViewState)
-
- // If the view isn't bound, we can drop the animation, otherwise we'll execute it
- animateNextStateChange = false
- if (transitionLayout == null) {
- return
- }
-
- val result: TransitionViewState
- var startViewState = obtainViewState(startHostState)
- startViewState = updateViewStateToCarouselSize(startViewState, startLocation, tmpState3)
+ ) =
+ traceSection("MediaViewController#setCurrentState") {
+ currentEndLocation = endLocation
+ currentStartLocation = startLocation
+ currentTransitionProgress = transitionProgress
+ logger.logMediaLocation("setCurrentState", startLocation, endLocation)
+
+ val shouldAnimate = animateNextStateChange && !applyImmediately
+
+ val endHostState = mediaHostStatesManager.mediaHostStates[endLocation] ?: return
+ val startHostState = mediaHostStatesManager.mediaHostStates[startLocation]
+
+ // Obtain the view state that we'd want to be at the end
+ // The view might not be bound yet or has never been measured and in that case will be
+ // reset once the state is fully available
+ var endViewState = obtainViewState(endHostState) ?: return
+ endViewState = updateViewStateToCarouselSize(endViewState, endLocation, tmpState2)!!
+ layoutController.setMeasureState(endViewState)
+
+ // If the view isn't bound, we can drop the animation, otherwise we'll execute it
+ animateNextStateChange = false
+ if (transitionLayout == null) {
+ return
+ }
- if (!endHostState.visible) {
- // Let's handle the case where the end is gone first. In this case we take the
- // start viewState and will make it gone
- if (startViewState == null || startHostState == null || !startHostState.visible) {
- // the start isn't a valid state, let's use the endstate directly
+ val result: TransitionViewState
+ var startViewState = obtainViewState(startHostState)
+ startViewState = updateViewStateToCarouselSize(startViewState, startLocation, tmpState3)
+
+ if (!endHostState.visible) {
+ // Let's handle the case where the end is gone first. In this case we take the
+ // start viewState and will make it gone
+ if (startViewState == null || startHostState == null || !startHostState.visible) {
+ // the start isn't a valid state, let's use the endstate directly
+ result = endViewState
+ } else {
+ // Let's get the gone presentation from the start state
+ result =
+ layoutController.getGoneState(
+ startViewState,
+ startHostState.disappearParameters,
+ transitionProgress,
+ tmpState
+ )
+ }
+ } else if (startHostState != null && !startHostState.visible) {
+ // We have a start state and it is gone.
+ // Let's get presentation from the endState
+ result =
+ layoutController.getGoneState(
+ endViewState,
+ endHostState.disappearParameters,
+ 1.0f - transitionProgress,
+ tmpState
+ )
+ } else if (transitionProgress == 1.0f || startViewState == null) {
+ // We're at the end. Let's use that state
result = endViewState
+ } else if (transitionProgress == 0.0f) {
+ // We're at the start. Let's use that state
+ result = startViewState
} else {
- // Let's get the gone presentation from the start state
- result = layoutController.getGoneState(startViewState,
- startHostState.disappearParameters,
+ result =
+ layoutController.getInterpolatedState(
+ startViewState,
+ endViewState,
transitionProgress,
- tmpState)
+ tmpState
+ )
}
- } else if (startHostState != null && !startHostState.visible) {
- // We have a start state and it is gone.
- // Let's get presentation from the endState
- result = layoutController.getGoneState(endViewState, endHostState.disappearParameters,
- 1.0f - transitionProgress,
- tmpState)
- } else if (transitionProgress == 1.0f || startViewState == null) {
- // We're at the end. Let's use that state
- result = endViewState
- } else if (transitionProgress == 0.0f) {
- // We're at the start. Let's use that state
- result = startViewState
- } else {
- result = layoutController.getInterpolatedState(startViewState, endViewState,
- transitionProgress, tmpState)
+ logger.logMediaSize("setCurrentState", result.width, result.height)
+ layoutController.setState(
+ result,
+ applyImmediately,
+ shouldAnimate,
+ animationDuration,
+ animationDelay
+ )
}
- logger.logMediaSize("setCurrentState", result.width, result.height)
- layoutController.setState(result, applyImmediately, shouldAnimate, animationDuration,
- animationDelay)
- }
private fun updateViewStateToCarouselSize(
viewState: TransitionViewState?,
@@ -558,8 +550,8 @@ class MediaViewController @Inject constructor(
}
/**
- * Retrieves the [TransitionViewState] and [MediaHostState] of a [@MediaLocation].
- * In the event of [location] not being visible, [locationWhenHidden] will be used instead.
+ * Retrieves the [TransitionViewState] and [MediaHostState] of a [@MediaLocation]. In the event
+ * of [location] not being visible, [locationWhenHidden] will be used instead.
*
* @param location Target
* @param locationWhenHidden Location that will be used when the target is not
@@ -576,40 +568,37 @@ class MediaViewController @Inject constructor(
* This updates the width the view will me measured with.
*/
fun onLocationPreChange(@MediaLocation newLocation: Int) {
- obtainViewStateForLocation(newLocation)?.let {
- layoutController.setMeasureState(it)
- }
+ obtainViewStateForLocation(newLocation)?.let { layoutController.setMeasureState(it) }
}
- /**
- * Request that the next state change should be animated with the given parameters.
- */
+ /** Request that the next state change should be animated with the given parameters. */
fun animatePendingStateChange(duration: Long, delay: Long) {
animateNextStateChange = true
animationDuration = duration
animationDelay = delay
}
- /**
- * Clear all existing measurements and refresh the state to match the view.
- */
- fun refreshState() = traceSection("MediaViewController#refreshState") {
- // Let's clear all of our measurements and recreate them!
- viewStates.clear()
- if (firstRefresh) {
- // This is the first bind, let's ensure we pre-cache all measurements. Otherwise
- // We'll just load these on demand.
- ensureAllMeasurements()
- firstRefresh = false
+ /** Clear all existing measurements and refresh the state to match the view. */
+ fun refreshState() =
+ traceSection("MediaViewController#refreshState") {
+ // Let's clear all of our measurements and recreate them!
+ viewStates.clear()
+ if (firstRefresh) {
+ // This is the first bind, let's ensure we pre-cache all measurements. Otherwise
+ // We'll just load these on demand.
+ ensureAllMeasurements()
+ firstRefresh = false
+ }
+ setCurrentState(
+ currentStartLocation,
+ currentEndLocation,
+ currentTransitionProgress,
+ applyImmediately = true
+ )
}
- setCurrentState(currentStartLocation, currentEndLocation, currentTransitionProgress,
- applyImmediately = true)
- }
}
-/**
- * An internal key for the cache of mediaViewStates. This is a subset of the full host state.
- */
+/** An internal key for the cache of mediaViewStates. This is a subset of the full host state. */
private data class CacheKey(
var widthMeasureSpec: Int = -1,
var heightMeasureSpec: Int = -1,
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
index 3929e894d971..fdac33ac20b0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewLogger.kt
@@ -24,40 +24,32 @@ import javax.inject.Inject
private const val TAG = "MediaView"
-/**
- * A buffered log for media view events that are too noisy for regular logging
- */
+/** A buffered log for media view events that are too noisy for regular logging */
@SysUISingleton
-class MediaViewLogger @Inject constructor(
- @MediaViewLog private val buffer: LogBuffer
-) {
+class MediaViewLogger @Inject constructor(@MediaViewLog private val buffer: LogBuffer) {
fun logMediaSize(reason: String, width: Int, height: Int) {
buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = reason
- int1 = width
- int2 = height
- },
- {
- "size ($str1): $int1 x $int2"
- }
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = reason
+ int1 = width
+ int2 = height
+ },
+ { "size ($str1): $int1 x $int2" }
)
}
fun logMediaLocation(reason: String, startLocation: Int, endLocation: Int) {
buffer.log(
- TAG,
- LogLevel.DEBUG,
- {
- str1 = reason
- int1 = startLocation
- int2 = endLocation
- },
- {
- "location ($str1): $int1 -> $int2"
- }
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = reason
+ int1 = startLocation
+ int2 = endLocation
+ },
+ { "location ($str1): $int1 -> $int2" }
)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MetadataAnimationHandler.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MetadataAnimationHandler.kt
index dc49fe42575e..1cdcf5ed2702 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MetadataAnimationHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MetadataAnimationHandler.kt
@@ -73,4 +73,4 @@ internal open class MetadataAnimationHandler(
exitAnimator.addListener(this)
enterAnimator.addListener(this)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
index 41d19e2fb1f1..e9b2cf2b18d1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/SquigglyProgress.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.media.controls.ui
import android.animation.Animator
@@ -23,8 +39,7 @@ import kotlin.math.cos
private const val TAG = "Squiggly"
private const val TWO_PI = (Math.PI * 2f).toFloat()
-@VisibleForTesting
-internal const val DISABLED_ALPHA = 77
+@VisibleForTesting internal const val DISABLED_ALPHA = 77
class SquigglyProgress : Drawable() {
@@ -86,26 +101,29 @@ class SquigglyProgress : Drawable() {
lastFrameTime = SystemClock.uptimeMillis()
}
heightAnimator?.cancel()
- heightAnimator = ValueAnimator.ofFloat(heightFraction, if (animate) 1f else 0f).apply {
- if (animate) {
- startDelay = 60
- duration = 800
- interpolator = Interpolators.EMPHASIZED_DECELERATE
- } else {
- duration = 550
- interpolator = Interpolators.STANDARD_DECELERATE
- }
- addUpdateListener {
- heightFraction = it.animatedValue as Float
- invalidateSelf()
- }
- addListener(object : AnimatorListenerAdapter() {
- override fun onAnimationEnd(animation: Animator?) {
- heightAnimator = null
+ heightAnimator =
+ ValueAnimator.ofFloat(heightFraction, if (animate) 1f else 0f).apply {
+ if (animate) {
+ startDelay = 60
+ duration = 800
+ interpolator = Interpolators.EMPHASIZED_DECELERATE
+ } else {
+ duration = 550
+ interpolator = Interpolators.STANDARD_DECELERATE
}
- })
- start()
- }
+ addUpdateListener {
+ heightFraction = it.animatedValue as Float
+ invalidateSelf()
+ }
+ addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationEnd(animation: Animator?) {
+ heightAnimator = null
+ }
+ }
+ )
+ start()
+ }
}
override fun draw(canvas: Canvas) {
@@ -120,9 +138,15 @@ class SquigglyProgress : Drawable() {
val progress = level / 10_000f
val totalWidth = bounds.width().toFloat()
val totalProgressPx = totalWidth * progress
- val waveProgressPx = totalWidth * (
- if (!transitionEnabled || progress > matchedWaveEndpoint) progress else
- lerp(minWaveEndpoint, matchedWaveEndpoint, lerpInv(0f, matchedWaveEndpoint, progress)))
+ val waveProgressPx =
+ totalWidth *
+ (if (!transitionEnabled || progress > matchedWaveEndpoint) progress
+ else
+ lerp(
+ minWaveEndpoint,
+ matchedWaveEndpoint,
+ lerpInv(0f, matchedWaveEndpoint, progress)
+ ))
// Build Wiggly Path
val waveStart = -phaseOffset - waveLength / 2f
@@ -132,10 +156,8 @@ class SquigglyProgress : Drawable() {
val computeAmplitude: (Float, Float) -> Float = { x, sign ->
if (transitionEnabled) {
val length = transitionPeriods * waveLength
- val coeff = lerpInvSat(
- waveProgressPx + length / 2f,
- waveProgressPx - length / 2f,
- x)
+ val coeff =
+ lerpInvSat(waveProgressPx + length / 2f, waveProgressPx - length / 2f, x)
sign * heightFraction * lineAmplitude * coeff
} else {
sign * heightFraction * lineAmplitude
@@ -156,10 +178,7 @@ class SquigglyProgress : Drawable() {
val nextX = currentX + dist
val midX = currentX + dist / 2
val nextAmp = computeAmplitude(nextX, waveSign)
- path.cubicTo(
- midX, currentAmp,
- midX, nextAmp,
- nextX, nextAmp)
+ path.cubicTo(midX, currentAmp, midX, nextAmp, nextX, nextAmp)
currentAmp = nextAmp
currentX = nextX
}
@@ -229,7 +248,7 @@ class SquigglyProgress : Drawable() {
private fun updateColors(tintColor: Int, alpha: Int) {
wavePaint.color = ColorUtils.setAlphaComponent(tintColor, alpha)
- linePaint.color = ColorUtils.setAlphaComponent(tintColor,
- (DISABLED_ALPHA * (alpha / 255f)).toInt())
+ linePaint.color =
+ ColorUtils.setAlphaComponent(tintColor, (DISABLED_ALPHA * (alpha / 255f)).toInt())
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFeatureFlag.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFeatureFlag.kt
index 2ba70c03a6d0..91dac6f1a528 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFeatureFlag.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFeatureFlag.kt
@@ -20,9 +20,7 @@ import android.content.Context
import com.android.systemui.util.Utils
import javax.inject.Inject
-/**
- * Provides access to the current value of the feature flag.
- */
+/** Provides access to the current value of the feature flag. */
class MediaFeatureFlag @Inject constructor(private val context: Context) {
val enabled
get() = Utils.useQsMediaPlayer(context)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
index 579ba473c08b..8d4931a5d08c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt
@@ -34,9 +34,7 @@ class MediaFlags @Inject constructor(private val featureFlags: FeatureFlags) {
return enabled || featureFlags.isEnabled(Flags.MEDIA_SESSION_ACTIONS)
}
- /**
- * Check whether we support displaying information about mute await connections.
- */
+ /** Check whether we support displaying information about mute await connections. */
fun areMuteAwaitConnectionsEnabled() = featureFlags.isEnabled(Flags.MEDIA_MUTE_AWAIT)
/**
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaUiEventLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaUiEventLogger.kt
index 08a566983115..3ad8c21e8a1e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaUiEventLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaUiEventLogger.kt
@@ -30,17 +30,13 @@ import javax.inject.Inject
private const val INSTANCE_ID_MAX = 1 shl 20
-/**
- * A helper class to log events related to the media controls
- */
+/** A helper class to log events related to the media controls */
@SysUISingleton
class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger) {
private val instanceIdSequence = InstanceIdSequence(INSTANCE_ID_MAX)
- /**
- * Get a new instance ID for a new media control
- */
+ /** Get a new instance ID for a new media control */
fun getNewInstanceId(): InstanceId {
return instanceIdSequence.newInstanceId()
}
@@ -51,12 +47,13 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
instanceId: InstanceId,
playbackLocation: Int
) {
- val event = when (playbackLocation) {
- MediaData.PLAYBACK_LOCAL -> MediaUiEvent.LOCAL_MEDIA_ADDED
- MediaData.PLAYBACK_CAST_LOCAL -> MediaUiEvent.CAST_MEDIA_ADDED
- MediaData.PLAYBACK_CAST_REMOTE -> MediaUiEvent.REMOTE_MEDIA_ADDED
- else -> throw IllegalArgumentException("Unknown playback location")
- }
+ val event =
+ when (playbackLocation) {
+ MediaData.PLAYBACK_LOCAL -> MediaUiEvent.LOCAL_MEDIA_ADDED
+ MediaData.PLAYBACK_CAST_LOCAL -> MediaUiEvent.CAST_MEDIA_ADDED
+ MediaData.PLAYBACK_CAST_REMOTE -> MediaUiEvent.REMOTE_MEDIA_ADDED
+ else -> throw IllegalArgumentException("Unknown playback location")
+ }
logger.logWithInstanceId(event, uid, packageName, instanceId)
}
@@ -66,12 +63,13 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
instanceId: InstanceId,
playbackLocation: Int
) {
- val event = when (playbackLocation) {
- MediaData.PLAYBACK_LOCAL -> MediaUiEvent.TRANSFER_TO_LOCAL
- MediaData.PLAYBACK_CAST_LOCAL -> MediaUiEvent.TRANSFER_TO_CAST
- MediaData.PLAYBACK_CAST_REMOTE -> MediaUiEvent.TRANSFER_TO_REMOTE
- else -> throw IllegalArgumentException("Unknown playback location")
- }
+ val event =
+ when (playbackLocation) {
+ MediaData.PLAYBACK_LOCAL -> MediaUiEvent.TRANSFER_TO_LOCAL
+ MediaData.PLAYBACK_CAST_LOCAL -> MediaUiEvent.TRANSFER_TO_CAST
+ MediaData.PLAYBACK_CAST_REMOTE -> MediaUiEvent.TRANSFER_TO_REMOTE
+ else -> throw IllegalArgumentException("Unknown playback location")
+ }
logger.logWithInstanceId(event, uid, packageName, instanceId)
}
@@ -110,8 +108,12 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
}
fun logLongPressSettings(uid: Int, packageName: String, instanceId: InstanceId) {
- logger.logWithInstanceId(MediaUiEvent.OPEN_SETTINGS_LONG_PRESS, uid, packageName,
- instanceId)
+ logger.logWithInstanceId(
+ MediaUiEvent.OPEN_SETTINGS_LONG_PRESS,
+ uid,
+ packageName,
+ instanceId
+ )
}
fun logCarouselSettings() {
@@ -120,12 +122,13 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
}
fun logTapAction(buttonId: Int, uid: Int, packageName: String, instanceId: InstanceId) {
- val event = when (buttonId) {
- R.id.actionPlayPause -> MediaUiEvent.TAP_ACTION_PLAY_PAUSE
- R.id.actionPrev -> MediaUiEvent.TAP_ACTION_PREV
- R.id.actionNext -> MediaUiEvent.TAP_ACTION_NEXT
- else -> MediaUiEvent.TAP_ACTION_OTHER
- }
+ val event =
+ when (buttonId) {
+ R.id.actionPlayPause -> MediaUiEvent.TAP_ACTION_PLAY_PAUSE
+ R.id.actionPrev -> MediaUiEvent.TAP_ACTION_PREV
+ R.id.actionNext -> MediaUiEvent.TAP_ACTION_NEXT
+ else -> MediaUiEvent.TAP_ACTION_OTHER
+ }
logger.logWithInstanceId(event, uid, packageName, instanceId)
}
@@ -143,148 +146,130 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
}
fun logCarouselPosition(@MediaLocation location: Int) {
- val event = when (location) {
- MediaHierarchyManager.LOCATION_QQS -> MediaUiEvent.MEDIA_CAROUSEL_LOCATION_QQS
- MediaHierarchyManager.LOCATION_QS -> MediaUiEvent.MEDIA_CAROUSEL_LOCATION_QS
- MediaHierarchyManager.LOCATION_LOCKSCREEN ->
- MediaUiEvent.MEDIA_CAROUSEL_LOCATION_LOCKSCREEN
- MediaHierarchyManager.LOCATION_DREAM_OVERLAY ->
- MediaUiEvent.MEDIA_CAROUSEL_LOCATION_DREAM
- else -> throw IllegalArgumentException("Unknown media carousel location $location")
- }
+ val event =
+ when (location) {
+ MediaHierarchyManager.LOCATION_QQS -> MediaUiEvent.MEDIA_CAROUSEL_LOCATION_QQS
+ MediaHierarchyManager.LOCATION_QS -> MediaUiEvent.MEDIA_CAROUSEL_LOCATION_QS
+ MediaHierarchyManager.LOCATION_LOCKSCREEN ->
+ MediaUiEvent.MEDIA_CAROUSEL_LOCATION_LOCKSCREEN
+ MediaHierarchyManager.LOCATION_DREAM_OVERLAY ->
+ MediaUiEvent.MEDIA_CAROUSEL_LOCATION_DREAM
+ else -> throw IllegalArgumentException("Unknown media carousel location $location")
+ }
logger.log(event)
}
fun logRecommendationAdded(packageName: String, instanceId: InstanceId) {
- logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_ADDED, 0, packageName,
- instanceId)
+ logger.logWithInstanceId(
+ MediaUiEvent.MEDIA_RECOMMENDATION_ADDED,
+ 0,
+ packageName,
+ instanceId
+ )
}
fun logRecommendationRemoved(packageName: String, instanceId: InstanceId) {
- logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_REMOVED, 0, packageName,
- instanceId)
+ logger.logWithInstanceId(
+ MediaUiEvent.MEDIA_RECOMMENDATION_REMOVED,
+ 0,
+ packageName,
+ instanceId
+ )
}
fun logRecommendationActivated(uid: Int, packageName: String, instanceId: InstanceId) {
- logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_ACTIVATED, uid, packageName,
- instanceId)
+ logger.logWithInstanceId(
+ MediaUiEvent.MEDIA_RECOMMENDATION_ACTIVATED,
+ uid,
+ packageName,
+ instanceId
+ )
}
fun logRecommendationItemTap(packageName: String, instanceId: InstanceId, position: Int) {
- logger.logWithInstanceIdAndPosition(MediaUiEvent.MEDIA_RECOMMENDATION_ITEM_TAP, 0,
- packageName, instanceId, position)
+ logger.logWithInstanceIdAndPosition(
+ MediaUiEvent.MEDIA_RECOMMENDATION_ITEM_TAP,
+ 0,
+ packageName,
+ instanceId,
+ position
+ )
}
fun logRecommendationCardTap(packageName: String, instanceId: InstanceId) {
- logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_CARD_TAP, 0, packageName,
- instanceId)
+ logger.logWithInstanceId(
+ MediaUiEvent.MEDIA_RECOMMENDATION_CARD_TAP,
+ 0,
+ packageName,
+ instanceId
+ )
}
fun logOpenBroadcastDialog(uid: Int, packageName: String, instanceId: InstanceId) {
- logger.logWithInstanceId(MediaUiEvent.MEDIA_OPEN_BROADCAST_DIALOG, uid, packageName,
- instanceId)
+ logger.logWithInstanceId(
+ MediaUiEvent.MEDIA_OPEN_BROADCAST_DIALOG,
+ uid,
+ packageName,
+ instanceId
+ )
}
}
enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum {
@UiEvent(doc = "A new media control was added for media playing locally on the device")
LOCAL_MEDIA_ADDED(1029),
-
@UiEvent(doc = "A new media control was added for media cast from the device")
CAST_MEDIA_ADDED(1030),
-
@UiEvent(doc = "A new media control was added for media playing remotely")
REMOTE_MEDIA_ADDED(1031),
-
@UiEvent(doc = "The media for an existing control was transferred to local playback")
TRANSFER_TO_LOCAL(1032),
-
@UiEvent(doc = "The media for an existing control was transferred to a cast device")
TRANSFER_TO_CAST(1033),
-
@UiEvent(doc = "The media for an existing control was transferred to a remote device")
TRANSFER_TO_REMOTE(1034),
-
- @UiEvent(doc = "A new resumable media control was added")
- RESUME_MEDIA_ADDED(1013),
-
+ @UiEvent(doc = "A new resumable media control was added") RESUME_MEDIA_ADDED(1013),
@UiEvent(doc = "An existing active media control was converted into resumable media")
ACTIVE_TO_RESUME(1014),
-
- @UiEvent(doc = "A media control timed out")
- MEDIA_TIMEOUT(1015),
-
- @UiEvent(doc = "A media control was removed from the carousel")
- MEDIA_REMOVED(1016),
-
- @UiEvent(doc = "User swiped to another control within the media carousel")
- CAROUSEL_PAGE(1017),
-
- @UiEvent(doc = "The user swiped away the media carousel")
- DISMISS_SWIPE(1018),
-
- @UiEvent(doc = "The user long pressed on a media control")
- OPEN_LONG_PRESS(1019),
-
+ @UiEvent(doc = "A media control timed out") MEDIA_TIMEOUT(1015),
+ @UiEvent(doc = "A media control was removed from the carousel") MEDIA_REMOVED(1016),
+ @UiEvent(doc = "User swiped to another control within the media carousel") CAROUSEL_PAGE(1017),
+ @UiEvent(doc = "The user swiped away the media carousel") DISMISS_SWIPE(1018),
+ @UiEvent(doc = "The user long pressed on a media control") OPEN_LONG_PRESS(1019),
@UiEvent(doc = "The user dismissed a media control via its long press menu")
DISMISS_LONG_PRESS(1020),
-
@UiEvent(doc = "The user opened media settings from a media control's long press menu")
OPEN_SETTINGS_LONG_PRESS(1021),
-
@UiEvent(doc = "The user opened media settings from the media carousel")
OPEN_SETTINGS_CAROUSEL(1022),
-
@UiEvent(doc = "The play/pause button on a media control was tapped")
TAP_ACTION_PLAY_PAUSE(1023),
-
- @UiEvent(doc = "The previous button on a media control was tapped")
- TAP_ACTION_PREV(1024),
-
- @UiEvent(doc = "The next button on a media control was tapped")
- TAP_ACTION_NEXT(1025),
-
+ @UiEvent(doc = "The previous button on a media control was tapped") TAP_ACTION_PREV(1024),
+ @UiEvent(doc = "The next button on a media control was tapped") TAP_ACTION_NEXT(1025),
@UiEvent(doc = "A custom or generic action button on a media control was tapped")
TAP_ACTION_OTHER(1026),
-
- @UiEvent(doc = "The user seeked on a media control using the seekbar")
- ACTION_SEEK(1027),
-
+ @UiEvent(doc = "The user seeked on a media control using the seekbar") ACTION_SEEK(1027),
@UiEvent(doc = "The user opened the output switcher from a media control")
OPEN_OUTPUT_SWITCHER(1028),
-
- @UiEvent(doc = "The user tapped on a media control view")
- MEDIA_TAP_CONTENT_VIEW(1036),
-
- @UiEvent(doc = "The media carousel moved to QQS")
- MEDIA_CAROUSEL_LOCATION_QQS(1037),
-
- @UiEvent(doc = "THe media carousel moved to QS")
- MEDIA_CAROUSEL_LOCATION_QS(1038),
-
+ @UiEvent(doc = "The user tapped on a media control view") MEDIA_TAP_CONTENT_VIEW(1036),
+ @UiEvent(doc = "The media carousel moved to QQS") MEDIA_CAROUSEL_LOCATION_QQS(1037),
+ @UiEvent(doc = "THe media carousel moved to QS") MEDIA_CAROUSEL_LOCATION_QS(1038),
@UiEvent(doc = "The media carousel moved to the lockscreen")
MEDIA_CAROUSEL_LOCATION_LOCKSCREEN(1039),
-
@UiEvent(doc = "The media carousel moved to the dream state")
MEDIA_CAROUSEL_LOCATION_DREAM(1040),
-
@UiEvent(doc = "A media recommendation card was added to the media carousel")
MEDIA_RECOMMENDATION_ADDED(1041),
-
@UiEvent(doc = "A media recommendation card was removed from the media carousel")
MEDIA_RECOMMENDATION_REMOVED(1042),
-
@UiEvent(doc = "An existing media control was made active as a recommendation")
MEDIA_RECOMMENDATION_ACTIVATED(1043),
-
@UiEvent(doc = "User tapped on an item in a media recommendation card")
MEDIA_RECOMMENDATION_ITEM_TAP(1044),
-
@UiEvent(doc = "User tapped on a media recommendation card")
MEDIA_RECOMMENDATION_CARD_TAP(1045),
-
@UiEvent(doc = "User opened the broadcast dialog from a media control")
MEDIA_OPEN_BROADCAST_DIALOG(1079);
override fun getId() = metricId
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/MediaTestUtils.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/MediaTestUtils.kt
index 04c4bc8edc43..3437365d9902 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/MediaTestUtils.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/MediaTestUtils.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.media.controls
import com.android.internal.logging.InstanceId
@@ -5,24 +21,26 @@ import com.android.systemui.media.controls.models.player.MediaData
class MediaTestUtils {
companion object {
- val emptyMediaData = MediaData(
- userId = 0,
- initialized = true,
- app = null,
- appIcon = null,
- artist = null,
- song = null,
- artwork = null,
- actions = emptyList(),
- actionsToShowInCompact = emptyList(),
- packageName = "",
- token = null,
- clickIntent = null,
- device = null,
- active = true,
- resumeAction = null,
- isPlaying = false,
- instanceId = InstanceId.fakeInstanceId(-1),
- appUid = -1)
+ val emptyMediaData =
+ MediaData(
+ userId = 0,
+ initialized = true,
+ app = null,
+ appIcon = null,
+ artist = null,
+ song = null,
+ artwork = null,
+ actions = emptyList(),
+ actionsToShowInCompact = emptyList(),
+ packageName = "",
+ token = null,
+ clickIntent = null,
+ device = null,
+ active = true,
+ resumeAction = null,
+ isPlaying = false,
+ instanceId = InstanceId.fakeInstanceId(-1),
+ appUid = -1
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/MediaViewHolderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/MediaViewHolderTest.kt
index e158966e3987..c829d4cbfb71 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/MediaViewHolderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/MediaViewHolderTest.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.media.controls.models.player
import android.testing.AndroidTestingRunner
@@ -21,4 +37,4 @@ class MediaViewHolderTest : SysuiTestCase() {
MediaViewHolder.create(inflater, parent)
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarObserverTest.kt
index ff09d97b96be..97b18e214550 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarObserverTest.kt
@@ -34,8 +34,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -57,10 +57,14 @@ class SeekBarObserverTest : SysuiTestCase() {
@Before
fun setUp() {
- context.orCreateTestableResources
- .addOverride(R.dimen.qs_media_enabled_seekbar_height, enabledHeight)
- context.orCreateTestableResources
- .addOverride(R.dimen.qs_media_disabled_seekbar_height, disabledHeight)
+ context.orCreateTestableResources.addOverride(
+ R.dimen.qs_media_enabled_seekbar_height,
+ enabledHeight
+ )
+ context.orCreateTestableResources.addOverride(
+ R.dimen.qs_media_disabled_seekbar_height,
+ disabledHeight
+ )
seekBarView = SeekBar(context)
seekBarView.progressDrawable = mockSquigglyProgress
@@ -70,11 +74,12 @@ class SeekBarObserverTest : SysuiTestCase() {
whenever(mockHolder.scrubbingElapsedTimeView).thenReturn(scrubbingElapsedTimeView)
whenever(mockHolder.scrubbingTotalTimeView).thenReturn(scrubbingTotalTimeView)
- observer = object : SeekBarObserver(mockHolder) {
- override fun buildResetAnimator(targetTime: Int): Animator {
- return mockSeekbarAnimator
+ observer =
+ object : SeekBarObserver(mockHolder) {
+ override fun buildResetAnimator(targetTime: Int): Animator {
+ return mockSeekbarAnimator
+ }
}
- }
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarViewModelTest.kt
index aa50db342303..7cd8e749a6e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/player/SeekBarViewModelTest.kt
@@ -57,17 +57,18 @@ public class SeekBarViewModelTest : SysuiTestCase() {
private lateinit var viewModel: SeekBarViewModel
private lateinit var fakeExecutor: FakeExecutor
- private val taskExecutor: TaskExecutor = object : TaskExecutor() {
- override fun executeOnDiskIO(runnable: Runnable) {
- runnable.run()
- }
- override fun postToMainThread(runnable: Runnable) {
- runnable.run()
- }
- override fun isMainThread(): Boolean {
- return true
+ private val taskExecutor: TaskExecutor =
+ object : TaskExecutor() {
+ override fun executeOnDiskIO(runnable: Runnable) {
+ runnable.run()
+ }
+ override fun postToMainThread(runnable: Runnable) {
+ runnable.run()
+ }
+ override fun isMainThread(): Boolean {
+ return true
+ }
}
- }
@Mock private lateinit var mockController: MediaController
@Mock private lateinit var mockTransport: MediaController.TransportControls
@Mock private lateinit var falsingManager: FalsingManager
@@ -81,7 +82,7 @@ public class SeekBarViewModelTest : SysuiTestCase() {
fun setUp() {
fakeExecutor = FakeExecutor(FakeSystemClock())
viewModel = SeekBarViewModel(FakeRepeatableExecutor(fakeExecutor), falsingManager)
- viewModel.logSeek = { }
+ viewModel.logSeek = {}
whenever(mockController.sessionToken).thenReturn(token1)
whenever(mockBar.context).thenReturn(context)
@@ -135,16 +136,18 @@ public class SeekBarViewModelTest : SysuiTestCase() {
fun updateDurationWithPlayback() {
// GIVEN that the duration is contained within the metadata
val duration = 12000L
- val metadata = MediaMetadata.Builder().run {
- putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
- build()
- }
+ val metadata =
+ MediaMetadata.Builder().run {
+ putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
+ build()
+ }
whenever(mockController.getMetadata()).thenReturn(metadata)
// AND a valid playback state (ie. media session is not destroyed)
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
viewModel.updateController(mockController)
@@ -158,10 +161,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
fun updateDurationWithoutPlayback() {
// GIVEN that the duration is contained within the metadata
val duration = 12000L
- val metadata = MediaMetadata.Builder().run {
- putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
- build()
- }
+ val metadata =
+ MediaMetadata.Builder().run {
+ putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
+ build()
+ }
whenever(mockController.getMetadata()).thenReturn(metadata)
// WHEN the controller is updated
viewModel.updateController(mockController)
@@ -174,16 +178,18 @@ public class SeekBarViewModelTest : SysuiTestCase() {
fun updateDurationNegative() {
// GIVEN that the duration is negative
val duration = -1L
- val metadata = MediaMetadata.Builder().run {
- putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
- build()
- }
+ val metadata =
+ MediaMetadata.Builder().run {
+ putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
+ build()
+ }
whenever(mockController.getMetadata()).thenReturn(metadata)
// AND a valid playback state (ie. media session is not destroyed)
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
viewModel.updateController(mockController)
@@ -195,16 +201,18 @@ public class SeekBarViewModelTest : SysuiTestCase() {
fun updateDurationZero() {
// GIVEN that the duration is zero
val duration = 0L
- val metadata = MediaMetadata.Builder().run {
- putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
- build()
- }
+ val metadata =
+ MediaMetadata.Builder().run {
+ putLong(MediaMetadata.METADATA_KEY_DURATION, duration)
+ build()
+ }
whenever(mockController.getMetadata()).thenReturn(metadata)
// AND a valid playback state (ie. media session is not destroyed)
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
viewModel.updateController(mockController)
@@ -218,10 +226,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
// GIVEN that the metadata is null
whenever(mockController.getMetadata()).thenReturn(null)
// AND a valid playback state (ie. media session is not destroyed)
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
viewModel.updateController(mockController)
@@ -233,10 +242,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
fun updateElapsedTime() {
// GIVEN that the PlaybackState contains the current position
val position = 200L
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, position, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, position, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
viewModel.updateController(mockController)
@@ -248,10 +258,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Ignore
fun updateSeekAvailable() {
// GIVEN that seek is included in actions
- val state = PlaybackState.Builder().run {
- setActions(PlaybackState.ACTION_SEEK_TO)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setActions(PlaybackState.ACTION_SEEK_TO)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
viewModel.updateController(mockController)
@@ -263,10 +274,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Ignore
fun updateSeekNotAvailable() {
// GIVEN that seek is not included in actions
- val state = PlaybackState.Builder().run {
- setActions(PlaybackState.ACTION_PLAY)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setActions(PlaybackState.ACTION_PLAY)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
viewModel.updateController(mockController)
@@ -318,9 +330,7 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Ignore
fun onSeekProgressWithSeekStarting() {
val pos = 42L
- with(viewModel) {
- onSeekProgress(pos)
- }
+ with(viewModel) { onSeekProgress(pos) }
fakeExecutor.runAllReady()
// THEN then elapsed time should not be updated
assertThat(viewModel.progress.value!!.elapsedTime).isNull()
@@ -329,11 +339,12 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Test
fun seekStarted_listenerNotified() {
var isScrubbing: Boolean? = null
- val listener = object : SeekBarViewModel.ScrubbingChangeListener {
- override fun onScrubbingChanged(scrubbing: Boolean) {
- isScrubbing = scrubbing
+ val listener =
+ object : SeekBarViewModel.ScrubbingChangeListener {
+ override fun onScrubbingChanged(scrubbing: Boolean) {
+ isScrubbing = scrubbing
+ }
}
- }
viewModel.setScrubbingChangeListener(listener)
viewModel.onSeekStarting()
@@ -345,11 +356,12 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Test
fun seekEnded_listenerNotified() {
var isScrubbing: Boolean? = null
- val listener = object : SeekBarViewModel.ScrubbingChangeListener {
- override fun onScrubbingChanged(scrubbing: Boolean) {
- isScrubbing = scrubbing
+ val listener =
+ object : SeekBarViewModel.ScrubbingChangeListener {
+ override fun onScrubbingChanged(scrubbing: Boolean) {
+ isScrubbing = scrubbing
+ }
}
- }
viewModel.setScrubbingChangeListener(listener)
// Start seeking
@@ -385,9 +397,7 @@ public class SeekBarViewModelTest : SysuiTestCase() {
val bar = SeekBar(context)
// WHEN we get an onProgressChanged event without an onStartTrackingTouch event
- with(viewModel.seekBarListener) {
- onProgressChanged(bar, pos, true)
- }
+ with(viewModel.seekBarListener) { onProgressChanged(bar, pos, true) }
fakeExecutor.runAllReady()
// THEN we immediately update the transport
@@ -412,9 +422,7 @@ public class SeekBarViewModelTest : SysuiTestCase() {
viewModel.updateController(mockController)
// WHEN user starts dragging the seek bar
val pos = 42
- val bar = SeekBar(context).apply {
- progress = pos
- }
+ val bar = SeekBar(context).apply { progress = pos }
viewModel.seekBarListener.onStartTrackingTouch(bar)
fakeExecutor.runAllReady()
// THEN transport controls should be used
@@ -427,9 +435,7 @@ public class SeekBarViewModelTest : SysuiTestCase() {
viewModel.updateController(mockController)
// WHEN user ends drag
val pos = 42
- val bar = SeekBar(context).apply {
- progress = pos
- }
+ val bar = SeekBar(context).apply { progress = pos }
viewModel.seekBarListener.onStopTrackingTouch(bar)
fakeExecutor.runAllReady()
// THEN transport controls should be used
@@ -443,9 +449,7 @@ public class SeekBarViewModelTest : SysuiTestCase() {
// WHEN user starts dragging the seek bar
val pos = 42
val progPos = 84
- val bar = SeekBar(context).apply {
- progress = pos
- }
+ val bar = SeekBar(context).apply { progress = pos }
with(viewModel.seekBarListener) {
onStartTrackingTouch(bar)
onProgressChanged(bar, progPos, true)
@@ -478,10 +482,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Test
fun queuePollTaskWhenPlaying() {
// GIVEN that the track is playing
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 100L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 100L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN the controller is updated
viewModel.updateController(mockController)
@@ -492,10 +497,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Test
fun noQueuePollTaskWhenStopped() {
// GIVEN that the playback state is stopped
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_STOPPED, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_STOPPED, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN updated
viewModel.updateController(mockController)
@@ -512,10 +518,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
runAllReady()
}
// AND the playback state is playing
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN updated
viewModel.updateController(mockController)
@@ -532,10 +539,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
runAllReady()
}
// AND the playback state is playing
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// WHEN updated
viewModel.updateController(mockController)
@@ -546,10 +554,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Test
fun pollTaskQueuesAnotherPollTaskWhenPlaying() {
// GIVEN that the track is playing
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 100L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 100L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
viewModel.updateController(mockController)
// WHEN the next task runs
@@ -566,10 +575,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
// GIVEN listening
viewModel.listening = true
// AND the playback state is playing
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
viewModel.updateController(mockController)
with(fakeExecutor) {
@@ -592,10 +602,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
// GIVEN listening
viewModel.listening = true
// AND the playback state is playing
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
viewModel.updateController(mockController)
with(fakeExecutor) {
@@ -621,10 +632,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
// GIVEN listening
viewModel.listening = true
// AND the playback state is playing
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
viewModel.updateController(mockController)
with(fakeExecutor) {
@@ -654,10 +666,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
runAllReady()
}
// AND the playback state is playing
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_STOPPED, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_STOPPED, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
viewModel.updateController(mockController)
// WHEN start listening
@@ -673,10 +686,11 @@ public class SeekBarViewModelTest : SysuiTestCase() {
verify(mockController).registerCallback(captor.capture())
val callback = captor.value
// WHEN the callback receives an new state
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 100L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 100L, 1f)
+ build()
+ }
callback.onPlaybackStateChanged(state)
with(fakeExecutor) {
advanceClockToNext()
@@ -690,16 +704,18 @@ public class SeekBarViewModelTest : SysuiTestCase() {
@Ignore
fun clearSeekBar() {
// GIVEN that the duration is contained within the metadata
- val metadata = MediaMetadata.Builder().run {
- putLong(MediaMetadata.METADATA_KEY_DURATION, 12000L)
- build()
- }
+ val metadata =
+ MediaMetadata.Builder().run {
+ putLong(MediaMetadata.METADATA_KEY_DURATION, 12000L)
+ build()
+ }
whenever(mockController.getMetadata()).thenReturn(metadata)
// AND a valid playback state (ie. media session is not destroyed)
- val state = PlaybackState.Builder().run {
- setState(PlaybackState.STATE_PLAYING, 200L, 1f)
- build()
- }
+ val state =
+ PlaybackState.Builder().run {
+ setState(PlaybackState.STATE_PLAYING, 200L, 1f)
+ build()
+ }
whenever(mockController.getPlaybackState()).thenReturn(state)
// AND the controller has been updated
viewModel.updateController(mockController)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataTest.kt
index 959bb6c3eb7b..1d6e980bdb86 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/models/recommendation/SmartspaceMediaDataTest.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.media.controls.models.recommendation
import android.app.smartspace.SmartspaceAction
@@ -36,11 +52,11 @@ class SmartspaceMediaDataTest : SysuiTestCase() {
@Test
fun isValid_tooFewRecs_returnsFalse() {
- val data = DEFAULT_DATA.copy(
- recommendations = listOf(
- SmartspaceAction.Builder("id", "title").setIcon(icon).build()
+ val data =
+ DEFAULT_DATA.copy(
+ recommendations =
+ listOf(SmartspaceAction.Builder("id", "title").setIcon(icon).build())
)
- )
assertThat(data.isValid()).isFalse()
}
@@ -50,14 +66,10 @@ class SmartspaceMediaDataTest : SysuiTestCase() {
val recommendations = mutableListOf<SmartspaceAction>()
// Add one fewer recommendation w/ icon than the number required
for (i in 1 until NUM_REQUIRED_RECOMMENDATIONS) {
- recommendations.add(
- SmartspaceAction.Builder("id", "title").setIcon(icon).build()
- )
+ recommendations.add(SmartspaceAction.Builder("id", "title").setIcon(icon).build())
}
for (i in 1 until 3) {
- recommendations.add(
- SmartspaceAction.Builder("id", "title").setIcon(null).build()
- )
+ recommendations.add(SmartspaceAction.Builder("id", "title").setIcon(null).build())
}
val data = DEFAULT_DATA.copy(recommendations = recommendations)
@@ -70,9 +82,7 @@ class SmartspaceMediaDataTest : SysuiTestCase() {
val recommendations = mutableListOf<SmartspaceAction>()
// Add the number of required recommendations
for (i in 0 until NUM_REQUIRED_RECOMMENDATIONS) {
- recommendations.add(
- SmartspaceAction.Builder("id", "title").setIcon(icon).build()
- )
+ recommendations.add(SmartspaceAction.Builder("id", "title").setIcon(icon).build())
}
val data = DEFAULT_DATA.copy(recommendations = recommendations)
@@ -85,9 +95,7 @@ class SmartspaceMediaDataTest : SysuiTestCase() {
val recommendations = mutableListOf<SmartspaceAction>()
// Add more than enough recommendations
for (i in 0 until NUM_REQUIRED_RECOMMENDATIONS + 3) {
- recommendations.add(
- SmartspaceAction.Builder("id", "title").setIcon(icon).build()
- )
+ recommendations.add(SmartspaceAction.Builder("id", "title").setIcon(icon).build())
}
val data = DEFAULT_DATA.copy(recommendations = recommendations)
@@ -96,13 +104,14 @@ class SmartspaceMediaDataTest : SysuiTestCase() {
}
}
-private val DEFAULT_DATA = SmartspaceMediaData(
- targetId = "INVALID",
- isActive = false,
- packageName = "INVALID",
- cardAction = null,
- recommendations = emptyList(),
- dismissIntent = null,
- headphoneConnectionTimeMillis = 0,
- instanceId = InstanceId.fakeInstanceId(-1)
-)
+private val DEFAULT_DATA =
+ SmartspaceMediaData(
+ targetId = "INVALID",
+ isActive = false,
+ packageName = "INVALID",
+ cardAction = null,
+ recommendations = emptyList(),
+ dismissIntent = null,
+ headphoneConnectionTimeMillis = 0,
+ instanceId = InstanceId.fakeInstanceId(-1)
+ )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataFilterTest.kt
index ac5e131ee068..575b1c6b126e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataFilterTest.kt
@@ -63,24 +63,15 @@ private val SMARTSPACE_INSTANCE_ID = InstanceId.fakeInstanceId(456)!!
@TestableLooper.RunWithLooper
class MediaDataFilterTest : SysuiTestCase() {
- @Mock
- private lateinit var listener: MediaDataManager.Listener
- @Mock
- private lateinit var broadcastDispatcher: BroadcastDispatcher
- @Mock
- private lateinit var broadcastSender: BroadcastSender
- @Mock
- private lateinit var mediaDataManager: MediaDataManager
- @Mock
- private lateinit var lockscreenUserManager: NotificationLockscreenUserManager
- @Mock
- private lateinit var executor: Executor
- @Mock
- private lateinit var smartspaceData: SmartspaceMediaData
- @Mock
- private lateinit var smartspaceMediaRecommendationItem: SmartspaceAction
- @Mock
- private lateinit var logger: MediaUiEventLogger
+ @Mock private lateinit var listener: MediaDataManager.Listener
+ @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock private lateinit var broadcastSender: BroadcastSender
+ @Mock private lateinit var mediaDataManager: MediaDataManager
+ @Mock private lateinit var lockscreenUserManager: NotificationLockscreenUserManager
+ @Mock private lateinit var executor: Executor
+ @Mock private lateinit var smartspaceData: SmartspaceMediaData
+ @Mock private lateinit var smartspaceMediaRecommendationItem: SmartspaceAction
+ @Mock private lateinit var logger: MediaUiEventLogger
private lateinit var mediaDataFilter: MediaDataFilter
private lateinit var dataMain: MediaData
@@ -91,14 +82,16 @@ class MediaDataFilterTest : SysuiTestCase() {
fun setup() {
MockitoAnnotations.initMocks(this)
MediaPlayerData.clear()
- mediaDataFilter = MediaDataFilter(
- context,
- broadcastDispatcher,
- broadcastSender,
- lockscreenUserManager,
- executor,
- clock,
- logger)
+ mediaDataFilter =
+ MediaDataFilter(
+ context,
+ broadcastDispatcher,
+ broadcastSender,
+ lockscreenUserManager,
+ executor,
+ clock,
+ logger
+ )
mediaDataFilter.mediaDataManager = mediaDataManager
mediaDataFilter.addListener(listener)
@@ -106,11 +99,13 @@ class MediaDataFilterTest : SysuiTestCase() {
setUser(USER_MAIN)
// Set up test media data
- dataMain = MediaTestUtils.emptyMediaData.copy(
+ dataMain =
+ MediaTestUtils.emptyMediaData.copy(
userId = USER_MAIN,
packageName = PACKAGE,
instanceId = INSTANCE_ID,
- appUid = APP_UID)
+ appUid = APP_UID
+ )
dataGuest = dataMain.copy(userId = USER_GUEST)
`when`(smartspaceData.targetId).thenReturn(SMARTSPACE_KEY)
@@ -118,8 +113,8 @@ class MediaDataFilterTest : SysuiTestCase() {
`when`(smartspaceData.isValid()).thenReturn(true)
`when`(smartspaceData.packageName).thenReturn(SMARTSPACE_PACKAGE)
`when`(smartspaceData.recommendations).thenReturn(listOf(smartspaceMediaRecommendationItem))
- `when`(smartspaceData.headphoneConnectionTimeMillis).thenReturn(
- clock.currentTimeMillis() - 100)
+ `when`(smartspaceData.headphoneConnectionTimeMillis)
+ .thenReturn(clock.currentTimeMillis() - 100)
`when`(smartspaceData.instanceId).thenReturn(SMARTSPACE_INSTANCE_ID)
}
@@ -135,8 +130,8 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
// THEN we should tell the listener
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true),
- eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true), eq(0), eq(false))
}
@Test
@@ -145,8 +140,8 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest)
// THEN we should NOT tell the listener
- verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean(),
- anyInt(), anyBoolean())
+ verify(listener, never())
+ .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean())
}
@Test
@@ -192,12 +187,12 @@ class MediaDataFilterTest : SysuiTestCase() {
setUser(USER_GUEST)
// THEN we should add back the guest user media
- verify(listener).onMediaDataLoaded(eq(KEY_ALT), eq(null), eq(dataGuest), eq(true),
- eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY_ALT), eq(null), eq(dataGuest), eq(true), eq(0), eq(false))
// but not the main user's
- verify(listener, never()).onMediaDataLoaded(eq(KEY), any(), eq(dataMain), anyBoolean(),
- anyInt(), anyBoolean())
+ verify(listener, never())
+ .onMediaDataLoaded(eq(KEY), any(), eq(dataMain), anyBoolean(), anyInt(), anyBoolean())
}
@Test
@@ -345,7 +340,7 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener)
- .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
+ .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue()
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
@@ -358,8 +353,8 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
- verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean(),
- anyInt(), anyBoolean())
+ verify(listener, never())
+ .onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt(), anyBoolean())
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
@@ -375,7 +370,7 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener)
- .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
+ .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue()
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
@@ -405,15 +400,15 @@ class MediaDataFilterTest : SysuiTestCase() {
// WHEN we have media that was recently played, but not currently active
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true),
- eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
// AND we get a smartspace signal
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
// THEN we should tell listeners to treat the media as not active instead
- verify(listener, never()).onMediaDataLoaded(eq(KEY), eq(KEY), any(), anyBoolean(),
- anyInt(), anyBoolean())
+ verify(listener, never())
+ .onMediaDataLoaded(eq(KEY), eq(KEY), any(), anyBoolean(), anyInt(), anyBoolean())
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
@@ -428,16 +423,23 @@ class MediaDataFilterTest : SysuiTestCase() {
// WHEN we have media that was recently played, but not currently active
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true),
- eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
// AND we get a smartspace signal
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
// THEN we should tell listeners to treat the media as active instead
val dataCurrentAndActive = dataCurrent.copy(active = true)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true),
- eq(100), eq(true))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ eq(dataCurrentAndActive),
+ eq(true),
+ eq(100),
+ eq(true)
+ )
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue()
// Smartspace update shouldn't be propagated for the empty rec list.
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
@@ -450,20 +452,27 @@ class MediaDataFilterTest : SysuiTestCase() {
// WHEN we have media that was recently played, but not currently active
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true),
- eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
// AND we get a smartspace signal
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
// THEN we should tell listeners to treat the media as active instead
val dataCurrentAndActive = dataCurrent.copy(active = true)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true),
- eq(100), eq(true))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ eq(dataCurrentAndActive),
+ eq(true),
+ eq(100),
+ eq(true)
+ )
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue()
// Smartspace update should also be propagated but not prioritized.
verify(listener)
- .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
+ .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID))
}
@@ -482,14 +491,21 @@ class MediaDataFilterTest : SysuiTestCase() {
fun testOnSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBoth() {
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true),
- eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true), eq(0), eq(false))
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
val dataCurrentAndActive = dataCurrent.copy(active = true)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true),
- eq(100), eq(true))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ eq(dataCurrentAndActive),
+ eq(true),
+ eq(100),
+ eq(true)
+ )
mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
index 1f31aaece8a8..11eb26b1da02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
@@ -1,3 +1,19 @@
+/*
+ * 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.media.controls.pipeline
import android.app.Notification
@@ -118,58 +134,68 @@ class MediaDataManagerTest : SysuiTestCase() {
private val instanceIdSequence = InstanceIdSequenceFake(1 shl 20)
- private val originalSmartspaceSetting = Settings.Secure.getInt(context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 1)
+ private val originalSmartspaceSetting =
+ Settings.Secure.getInt(
+ context.contentResolver,
+ Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
+ 1
+ )
@Before
fun setup() {
foregroundExecutor = FakeExecutor(clock)
backgroundExecutor = FakeExecutor(clock)
smartspaceMediaDataProvider = SmartspaceMediaDataProvider()
- Settings.Secure.putInt(context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 1)
- mediaDataManager = MediaDataManager(
- context = context,
- backgroundExecutor = backgroundExecutor,
- foregroundExecutor = foregroundExecutor,
- mediaControllerFactory = mediaControllerFactory,
- broadcastDispatcher = broadcastDispatcher,
- dumpManager = dumpManager,
- mediaTimeoutListener = mediaTimeoutListener,
- mediaResumeListener = mediaResumeListener,
- mediaSessionBasedFilter = mediaSessionBasedFilter,
- mediaDeviceManager = mediaDeviceManager,
- mediaDataCombineLatest = mediaDataCombineLatest,
- mediaDataFilter = mediaDataFilter,
- activityStarter = activityStarter,
- smartspaceMediaDataProvider = smartspaceMediaDataProvider,
- useMediaResumption = true,
- useQsMediaPlayer = true,
- systemClock = clock,
- tunerService = tunerService,
- mediaFlags = mediaFlags,
- logger = logger
+ Settings.Secure.putInt(
+ context.contentResolver,
+ Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
+ 1
)
- verify(tunerService).addTunable(capture(tunableCaptor),
- eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION))
+ mediaDataManager =
+ MediaDataManager(
+ context = context,
+ backgroundExecutor = backgroundExecutor,
+ foregroundExecutor = foregroundExecutor,
+ mediaControllerFactory = mediaControllerFactory,
+ broadcastDispatcher = broadcastDispatcher,
+ dumpManager = dumpManager,
+ mediaTimeoutListener = mediaTimeoutListener,
+ mediaResumeListener = mediaResumeListener,
+ mediaSessionBasedFilter = mediaSessionBasedFilter,
+ mediaDeviceManager = mediaDeviceManager,
+ mediaDataCombineLatest = mediaDataCombineLatest,
+ mediaDataFilter = mediaDataFilter,
+ activityStarter = activityStarter,
+ smartspaceMediaDataProvider = smartspaceMediaDataProvider,
+ useMediaResumption = true,
+ useQsMediaPlayer = true,
+ systemClock = clock,
+ tunerService = tunerService,
+ mediaFlags = mediaFlags,
+ logger = logger
+ )
+ verify(tunerService)
+ .addTunable(capture(tunableCaptor), eq(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION))
session = MediaSession(context, "MediaDataManagerTestSession")
- mediaNotification = SbnBuilder().run {
- setPkg(PACKAGE_NAME)
- modifyNotification(context).also {
- it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
+ mediaNotification =
+ SbnBuilder().run {
+ setPkg(PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
+ }
+ build()
+ }
+ metadataBuilder =
+ MediaMetadata.Builder().apply {
+ putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
+ putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
}
- build()
- }
- metadataBuilder = MediaMetadata.Builder().apply {
- putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
- putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
- }
whenever(mediaControllerFactory.create(eq(session.sessionToken))).thenReturn(controller)
whenever(controller.transportControls).thenReturn(transportControls)
whenever(controller.playbackInfo).thenReturn(playbackInfo)
- whenever(playbackInfo.playbackType).thenReturn(
- MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL)
+ whenever(playbackInfo.playbackType)
+ .thenReturn(MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL)
// This is an ugly hack for now. The mediaSessionBasedFilter is one of the internal
// listeners in the internal processing pipeline. It receives events, but ince it is a
@@ -177,18 +203,18 @@ class MediaDataManagerTest : SysuiTestCase() {
// treat mediaSessionBasedFilter as a listener for testing.
listener = mediaSessionBasedFilter
- val recommendationExtras = Bundle().apply {
- putString("package_name", PACKAGE_NAME)
- putParcelable("dismiss_intent", DISMISS_INTENT)
- }
+ val recommendationExtras =
+ Bundle().apply {
+ putString("package_name", PACKAGE_NAME)
+ putParcelable("dismiss_intent", DISMISS_INTENT)
+ }
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
whenever(mediaSmartspaceBaseAction.extras).thenReturn(recommendationExtras)
whenever(mediaSmartspaceTarget.baseAction).thenReturn(mediaSmartspaceBaseAction)
whenever(mediaRecommendationItem.extras).thenReturn(recommendationExtras)
whenever(mediaRecommendationItem.icon).thenReturn(icon)
- validRecommendationList = listOf(
- mediaRecommendationItem, mediaRecommendationItem, mediaRecommendationItem
- )
+ validRecommendationList =
+ listOf(mediaRecommendationItem, mediaRecommendationItem, mediaRecommendationItem)
whenever(mediaSmartspaceTarget.smartspaceTargetId).thenReturn(KEY_MEDIA_SMARTSPACE)
whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(validRecommendationList)
@@ -201,8 +227,11 @@ class MediaDataManagerTest : SysuiTestCase() {
fun tearDown() {
session.release()
mediaDataManager.destroy()
- Settings.Secure.putInt(context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, originalSmartspaceSetting)
+ Settings.Secure.putInt(
+ context.contentResolver,
+ Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
+ originalSmartspaceSetting
+ )
}
@Test
@@ -219,21 +248,36 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testSetTimedOut_resume_dismissesMedia() {
// WHEN resume controls are present, and time out
- val desc = MediaDescription.Builder().run {
- setTitle(SESSION_TITLE)
- build()
- }
- mediaDataManager.addResumptionControls(USER_ID, desc, Runnable {}, session.sessionToken,
- APP_NAME, pendingIntent, PACKAGE_NAME)
+ val desc =
+ MediaDescription.Builder().run {
+ setTitle(SESSION_TITLE)
+ build()
+ }
+ mediaDataManager.addResumptionControls(
+ USER_ID,
+ desc,
+ Runnable {},
+ session.sessionToken,
+ APP_NAME,
+ pendingIntent,
+ PACKAGE_NAME
+ )
backgroundExecutor.runAllReady()
foregroundExecutor.runAllReady()
- verify(listener).onMediaDataLoaded(eq(PACKAGE_NAME), eq(null), capture(mediaDataCaptor),
- eq(true), eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
mediaDataManager.setTimedOut(PACKAGE_NAME, timedOut = true)
- verify(logger).logMediaTimeout(anyInt(), eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId))
+ verify(logger)
+ .logMediaTimeout(anyInt(), eq(PACKAGE_NAME), eq(mediaDataCaptor.value.instanceId))
// THEN it is removed and listeners are informed
foregroundExecutor.advanceClockToLast()
@@ -250,8 +294,13 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testOnMetaDataLoaded_callsListener() {
addNotificationAndLoad()
- verify(logger).logActiveMediaAdded(anyInt(), eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId), eq(MediaData.PLAYBACK_LOCAL))
+ verify(logger)
+ .logActiveMediaAdded(
+ anyInt(),
+ eq(PACKAGE_NAME),
+ eq(mediaDataCaptor.value.instanceId),
+ eq(MediaData.PLAYBACK_LOCAL)
+ )
}
@Test
@@ -262,56 +311,85 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value!!.active).isTrue()
}
@Test
fun testOnNotificationAdded_isRcn_markedRemote() {
- val rcn = SbnBuilder().run {
- setPkg(SYSTEM_PACKAGE_NAME)
- modifyNotification(context).also {
- it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.setStyle(MediaStyle().apply {
- setMediaSession(session.sessionToken)
- setRemotePlaybackInfo("Remote device", 0, null)
- })
+ val rcn =
+ SbnBuilder().run {
+ setPkg(SYSTEM_PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.setStyle(
+ MediaStyle().apply {
+ setMediaSession(session.sessionToken)
+ setRemotePlaybackInfo("Remote device", 0, null)
+ }
+ )
+ }
+ build()
}
- build()
- }
mediaDataManager.onNotificationAdded(KEY, rcn)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
- assertThat(mediaDataCaptor.value!!.playbackLocation).isEqualTo(
- MediaData.PLAYBACK_CAST_REMOTE)
- verify(logger).logActiveMediaAdded(anyInt(), eq(SYSTEM_PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId), eq(MediaData.PLAYBACK_CAST_REMOTE))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ assertThat(mediaDataCaptor.value!!.playbackLocation)
+ .isEqualTo(MediaData.PLAYBACK_CAST_REMOTE)
+ verify(logger)
+ .logActiveMediaAdded(
+ anyInt(),
+ eq(SYSTEM_PACKAGE_NAME),
+ eq(mediaDataCaptor.value.instanceId),
+ eq(MediaData.PLAYBACK_CAST_REMOTE)
+ )
}
@Test
fun testOnNotificationAdded_hasSubstituteName_isUsed() {
val subName = "Substitute Name"
- val notif = SbnBuilder().run {
- modifyNotification(context).also {
- it.extras = Bundle().apply {
- putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName)
+ val notif =
+ SbnBuilder().run {
+ modifyNotification(context).also {
+ it.extras =
+ Bundle().apply {
+ putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName)
+ }
+ it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
}
- it.setStyle(MediaStyle().apply {
- setMediaSession(session.sessionToken)
- })
+ build()
}
- build()
- }
mediaDataManager.onNotificationAdded(KEY, notif)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value!!.app).isEqualTo(subName)
}
@@ -321,17 +399,18 @@ class MediaDataManagerTest : SysuiTestCase() {
val bundle = Bundle()
// wrong data type
bundle.putParcelable(Notification.EXTRA_MEDIA_SESSION, Bundle())
- val rcn = SbnBuilder().run {
- setPkg(SYSTEM_PACKAGE_NAME)
- modifyNotification(context).also {
- it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.addExtras(bundle)
- it.setStyle(MediaStyle().apply {
- setRemotePlaybackInfo("Remote device", 0, null)
- })
+ val rcn =
+ SbnBuilder().run {
+ setPkg(SYSTEM_PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.addExtras(bundle)
+ it.setStyle(
+ MediaStyle().apply { setRemotePlaybackInfo("Remote device", 0, null) }
+ )
+ }
+ build()
}
- build()
- }
mediaDataManager.loadMediaDataInBg(KEY, rcn, null)
// no crash even though the data structure is incorrect
@@ -342,18 +421,21 @@ class MediaDataManagerTest : SysuiTestCase() {
val bundle = Bundle()
// wrong data type
bundle.putParcelable(Notification.EXTRA_MEDIA_REMOTE_INTENT, Bundle())
- val rcn = SbnBuilder().run {
- setPkg(SYSTEM_PACKAGE_NAME)
- modifyNotification(context).also {
- it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.addExtras(bundle)
- it.setStyle(MediaStyle().apply {
- setMediaSession(session.sessionToken)
- setRemotePlaybackInfo("Remote device", 0, null)
- })
+ val rcn =
+ SbnBuilder().run {
+ setPkg(SYSTEM_PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.addExtras(bundle)
+ it.setStyle(
+ MediaStyle().apply {
+ setMediaSession(session.sessionToken)
+ setRemotePlaybackInfo("Remote device", 0, null)
+ }
+ )
+ }
+ build()
}
- build()
- }
mediaDataManager.loadMediaDataInBg(KEY, rcn, null)
// no crash even though the data structure is incorrect
@@ -380,8 +462,14 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onNotificationRemoved(KEY)
// THEN the media data indicates that it is for resumption
verify(listener)
- .onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
verify(logger).logActiveConvertedToResume(anyInt(), eq(PACKAGE_NAME), eq(data.instanceId))
@@ -396,8 +484,14 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(backgroundExecutor.runAllReady()).isEqualTo(2)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(2)
verify(listener)
- .onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse()
val resumableData = data.copy(resumeAction = Runnable {})
@@ -408,8 +502,14 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onNotificationRemoved(KEY)
// THEN the data is for resumption and the key is migrated to the package name
verify(listener)
- .onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value.resumption).isTrue()
verify(listener, never()).onMediaDataRemoved(eq(KEY))
// WHEN the second is removed
@@ -417,8 +517,13 @@ class MediaDataManagerTest : SysuiTestCase() {
// THEN the data is for resumption and the second key is removed
verify(listener)
.onMediaDataLoaded(
- eq(PACKAGE_NAME), eq(PACKAGE_NAME), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ eq(PACKAGE_NAME),
+ eq(PACKAGE_NAME),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value.resumption).isTrue()
verify(listener).onMediaDataRemoved(eq(KEY_2))
}
@@ -427,15 +532,20 @@ class MediaDataManagerTest : SysuiTestCase() {
fun testOnNotificationRemoved_withResumption_butNotLocal() {
// GIVEN that the manager has a notification with a resume action, but is not local
whenever(controller.metadata).thenReturn(metadataBuilder.build())
- whenever(playbackInfo.playbackType).thenReturn(
- MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+ whenever(playbackInfo.playbackType)
+ .thenReturn(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE)
addNotificationAndLoad()
val data = mediaDataCaptor.value
- val dataRemoteWithResume = data.copy(resumeAction = Runnable {},
- playbackLocation = MediaData.PLAYBACK_CAST_LOCAL)
+ val dataRemoteWithResume =
+ data.copy(resumeAction = Runnable {}, playbackLocation = MediaData.PLAYBACK_CAST_LOCAL)
mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
- verify(logger).logActiveMediaAdded(anyInt(), eq(PACKAGE_NAME),
- eq(mediaDataCaptor.value.instanceId), eq(MediaData.PLAYBACK_CAST_LOCAL))
+ verify(logger)
+ .logActiveMediaAdded(
+ anyInt(),
+ eq(PACKAGE_NAME),
+ eq(mediaDataCaptor.value.instanceId),
+ eq(MediaData.PLAYBACK_CAST_LOCAL)
+ )
// WHEN the notification is removed
mediaDataManager.onNotificationRemoved(KEY)
@@ -447,19 +557,33 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testAddResumptionControls() {
// WHEN resumption controls are added
- val desc = MediaDescription.Builder().run {
- setTitle(SESSION_TITLE)
- build()
- }
+ val desc =
+ MediaDescription.Builder().run {
+ setTitle(SESSION_TITLE)
+ build()
+ }
val currentTime = clock.elapsedRealtime()
- mediaDataManager.addResumptionControls(USER_ID, desc, Runnable {}, session.sessionToken,
- APP_NAME, pendingIntent, PACKAGE_NAME)
+ mediaDataManager.addResumptionControls(
+ USER_ID,
+ desc,
+ Runnable {},
+ session.sessionToken,
+ APP_NAME,
+ pendingIntent,
+ PACKAGE_NAME
+ )
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
// THEN the media data indicates that it is for resumption
verify(listener)
- .onMediaDataLoaded(eq(PACKAGE_NAME), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
val data = mediaDataCaptor.value
assertThat(data.resumption).isTrue()
assertThat(data.song).isEqualTo(SESSION_TITLE)
@@ -473,16 +597,31 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testResumptionDisabled_dismissesResumeControls() {
// WHEN there are resume controls and resumption is switched off
- val desc = MediaDescription.Builder().run {
- setTitle(SESSION_TITLE)
- build()
- }
- mediaDataManager.addResumptionControls(USER_ID, desc, Runnable {}, session.sessionToken,
- APP_NAME, pendingIntent, PACKAGE_NAME)
+ val desc =
+ MediaDescription.Builder().run {
+ setTitle(SESSION_TITLE)
+ build()
+ }
+ mediaDataManager.addResumptionControls(
+ USER_ID,
+ desc,
+ Runnable {},
+ session.sessionToken,
+ APP_NAME,
+ pendingIntent,
+ PACKAGE_NAME
+ )
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(PACKAGE_NAME), eq(null), capture(mediaDataCaptor),
- eq(true), eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
val data = mediaDataCaptor.value
mediaDataManager.setMediaResumptionEnabled(false)
@@ -515,23 +654,30 @@ class MediaDataManagerTest : SysuiTestCase() {
fun testBadArtwork_doesNotUse() {
// WHEN notification has a too-small artwork
val artwork = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
- val notif = SbnBuilder().run {
- setPkg(PACKAGE_NAME)
- modifyNotification(context).also {
- it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
- it.setLargeIcon(artwork)
+ val notif =
+ SbnBuilder().run {
+ setPkg(PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
+ it.setLargeIcon(artwork)
+ }
+ build()
}
- build()
- }
mediaDataManager.onNotificationAdded(KEY, notif)
// THEN it still loads
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener)
- .onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
}
@Test
@@ -540,18 +686,23 @@ class MediaDataManagerTest : SysuiTestCase() {
verify(logger).getNewInstanceId()
val instanceId = instanceIdSequence.lastInstanceId
- verify(listener).onSmartspaceMediaDataLoaded(
- eq(KEY_MEDIA_SMARTSPACE),
- eq(SmartspaceMediaData(
- targetId = KEY_MEDIA_SMARTSPACE,
- isActive = true,
- packageName = PACKAGE_NAME,
- cardAction = mediaSmartspaceBaseAction,
- recommendations = validRecommendationList,
- dismissIntent = DISMISS_INTENT,
- headphoneConnectionTimeMillis = 1234L,
- instanceId = InstanceId.fakeInstanceId(instanceId))),
- eq(false))
+ verify(listener)
+ .onSmartspaceMediaDataLoaded(
+ eq(KEY_MEDIA_SMARTSPACE),
+ eq(
+ SmartspaceMediaData(
+ targetId = KEY_MEDIA_SMARTSPACE,
+ isActive = true,
+ packageName = PACKAGE_NAME,
+ cardAction = mediaSmartspaceBaseAction,
+ recommendations = validRecommendationList,
+ dismissIntent = DISMISS_INTENT,
+ headphoneConnectionTimeMillis = 1234L,
+ instanceId = InstanceId.fakeInstanceId(instanceId)
+ )
+ ),
+ eq(false)
+ )
}
@Test
@@ -561,23 +712,29 @@ class MediaDataManagerTest : SysuiTestCase() {
verify(logger).getNewInstanceId()
val instanceId = instanceIdSequence.lastInstanceId
- verify(listener).onSmartspaceMediaDataLoaded(
- eq(KEY_MEDIA_SMARTSPACE),
- eq(EMPTY_SMARTSPACE_MEDIA_DATA.copy(
- targetId = KEY_MEDIA_SMARTSPACE,
- isActive = true,
- dismissIntent = DISMISS_INTENT,
- headphoneConnectionTimeMillis = 1234L,
- instanceId = InstanceId.fakeInstanceId(instanceId))),
- eq(false))
+ verify(listener)
+ .onSmartspaceMediaDataLoaded(
+ eq(KEY_MEDIA_SMARTSPACE),
+ eq(
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ targetId = KEY_MEDIA_SMARTSPACE,
+ isActive = true,
+ dismissIntent = DISMISS_INTENT,
+ headphoneConnectionTimeMillis = 1234L,
+ instanceId = InstanceId.fakeInstanceId(instanceId)
+ )
+ ),
+ eq(false)
+ )
}
@Test
fun testOnSmartspaceMediaDataLoaded_hasNullIntent_callsListener() {
- val recommendationExtras = Bundle().apply {
- putString("package_name", PACKAGE_NAME)
- putParcelable("dismiss_intent", null)
- }
+ val recommendationExtras =
+ Bundle().apply {
+ putString("package_name", PACKAGE_NAME)
+ putParcelable("dismiss_intent", null)
+ }
whenever(mediaSmartspaceBaseAction.extras).thenReturn(recommendationExtras)
whenever(mediaSmartspaceTarget.baseAction).thenReturn(mediaSmartspaceBaseAction)
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf())
@@ -586,15 +743,20 @@ class MediaDataManagerTest : SysuiTestCase() {
verify(logger).getNewInstanceId()
val instanceId = instanceIdSequence.lastInstanceId
- verify(listener).onSmartspaceMediaDataLoaded(
- eq(KEY_MEDIA_SMARTSPACE),
- eq(EMPTY_SMARTSPACE_MEDIA_DATA.copy(
- targetId = KEY_MEDIA_SMARTSPACE,
- isActive = true,
- dismissIntent = null,
- headphoneConnectionTimeMillis = 1234L,
- instanceId = InstanceId.fakeInstanceId(instanceId))),
- eq(false))
+ verify(listener)
+ .onSmartspaceMediaDataLoaded(
+ eq(KEY_MEDIA_SMARTSPACE),
+ eq(
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ targetId = KEY_MEDIA_SMARTSPACE,
+ isActive = true,
+ dismissIntent = null,
+ headphoneConnectionTimeMillis = 1234L,
+ instanceId = InstanceId.fakeInstanceId(instanceId)
+ )
+ ),
+ eq(false)
+ )
}
@Test
@@ -602,7 +764,7 @@ class MediaDataManagerTest : SysuiTestCase() {
smartspaceMediaDataProvider.onTargetsAvailable(listOf())
verify(logger, never()).getNewInstanceId()
verify(listener, never())
- .onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean())
+ .onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean())
}
@Ignore("b/233283726")
@@ -622,15 +784,18 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testOnSmartspaceMediaDataLoaded_settingDisabled_doesNothing() {
// WHEN media recommendation setting is off
- Settings.Secure.putInt(context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 0)
+ Settings.Secure.putInt(
+ context.contentResolver,
+ Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
+ 0
+ )
tunableCaptor.value.onTuningChanged(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, "0")
smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
// THEN smartspace signal is ignored
verify(listener, never())
- .onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean())
+ .onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean())
}
@Ignore("b/229838140")
@@ -638,12 +803,15 @@ class MediaDataManagerTest : SysuiTestCase() {
fun testMediaRecommendationDisabled_removesSmartspaceData() {
// GIVEN a media recommendation card is present
smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
- verify(listener).onSmartspaceMediaDataLoaded(eq(KEY_MEDIA_SMARTSPACE), anyObject(),
- anyBoolean())
+ verify(listener)
+ .onSmartspaceMediaDataLoaded(eq(KEY_MEDIA_SMARTSPACE), anyObject(), anyBoolean())
// WHEN the media recommendation setting is turned off
- Settings.Secure.putInt(context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, 0)
+ Settings.Secure.putInt(
+ context.contentResolver,
+ Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION,
+ 0
+ )
tunableCaptor.value.onTuningChanged(Settings.Secure.MEDIA_CONTROLS_RECOMMENDATION, "0")
// THEN listeners are notified
@@ -672,8 +840,15 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.setTimedOut(KEY, true, true)
// THEN the last active time is not changed
- verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
}
@@ -694,8 +869,14 @@ class MediaDataManagerTest : SysuiTestCase() {
// THEN the last active time is not changed
verify(listener)
- .onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
@@ -707,17 +888,20 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testTooManyCompactActions_isTruncated() {
// GIVEN a notification where too many compact actions were specified
- val notif = SbnBuilder().run {
- setPkg(PACKAGE_NAME)
- modifyNotification(context).also {
- it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.setStyle(MediaStyle().apply {
- setMediaSession(session.sessionToken)
- setShowActionsInCompactView(0, 1, 2, 3, 4)
- })
+ val notif =
+ SbnBuilder().run {
+ setPkg(PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.setStyle(
+ MediaStyle().apply {
+ setMediaSession(session.sessionToken)
+ setShowActionsInCompactView(0, 1, 2, 3, 4)
+ }
+ )
+ }
+ build()
}
- build()
- }
// WHEN the notification is loaded
mediaDataManager.onNotificationAdded(KEY, notif)
@@ -725,29 +909,35 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
// THEN only the first MAX_COMPACT_ACTIONS are actually set
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
- assertThat(mediaDataCaptor.value.actionsToShowInCompact.size).isEqualTo(
- MediaDataManager.MAX_COMPACT_ACTIONS)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ assertThat(mediaDataCaptor.value.actionsToShowInCompact.size)
+ .isEqualTo(MediaDataManager.MAX_COMPACT_ACTIONS)
}
@Test
fun testTooManyNotificationActions_isTruncated() {
// GIVEN a notification where too many notification actions are added
val action = Notification.Action(R.drawable.ic_android, "action", null)
- val notif = SbnBuilder().run {
- setPkg(PACKAGE_NAME)
- modifyNotification(context).also {
- it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.setStyle(MediaStyle().apply {
- setMediaSession(session.sessionToken)
- })
- for (i in 0..MediaDataManager.MAX_NOTIFICATION_ACTIONS) {
- it.addAction(action)
+ val notif =
+ SbnBuilder().run {
+ setPkg(PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
+ for (i in 0..MediaDataManager.MAX_NOTIFICATION_ACTIONS) {
+ it.addAction(action)
+ }
}
+ build()
}
- build()
- }
// WHEN the notification is loaded
mediaDataManager.onNotificationAdded(KEY, notif)
@@ -755,10 +945,17 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
// THEN only the first MAX_NOTIFICATION_ACTIONS are actually included
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
- assertThat(mediaDataCaptor.value.actions.size).isEqualTo(
- MediaDataManager.MAX_NOTIFICATION_ACTIONS)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ assertThat(mediaDataCaptor.value.actions.size)
+ .isEqualTo(MediaDataManager.MAX_NOTIFICATION_ACTIONS)
}
@Test
@@ -767,21 +964,29 @@ class MediaDataManagerTest : SysuiTestCase() {
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
whenever(controller.playbackState).thenReturn(null)
- val notifWithAction = SbnBuilder().run {
- setPkg(PACKAGE_NAME)
- modifyNotification(context).also {
- it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
- it.addAction(android.R.drawable.ic_media_play, desc, null)
+ val notifWithAction =
+ SbnBuilder().run {
+ setPkg(PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
+ it.addAction(android.R.drawable.ic_media_play, desc, null)
+ }
+ build()
}
- build()
- }
mediaDataManager.onNotificationAdded(KEY, notifWithAction)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value!!.semanticActions).isNull()
assertThat(mediaDataCaptor.value!!.actions).hasSize(1)
@@ -792,11 +997,11 @@ class MediaDataManagerTest : SysuiTestCase() {
fun testPlaybackActions_hasPrevNext() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
- val stateActions = PlaybackState.ACTION_PLAY or
+ val stateActions =
+ PlaybackState.ACTION_PLAY or
PlaybackState.ACTION_SKIP_TO_PREVIOUS or
PlaybackState.ACTION_SKIP_TO_NEXT
- val stateBuilder = PlaybackState.Builder()
- .setActions(stateActions)
+ val stateBuilder = PlaybackState.Builder().setActions(stateActions)
customDesc.forEach {
stateBuilder.addCustomAction("action: $it", it, android.R.drawable.ic_media_pause)
}
@@ -808,20 +1013,20 @@ class MediaDataManagerTest : SysuiTestCase() {
val actions = mediaDataCaptor.value!!.semanticActions!!
assertThat(actions.playOrPause).isNotNull()
- assertThat(actions.playOrPause!!.contentDescription).isEqualTo(
- context.getString(R.string.controls_media_button_play))
+ assertThat(actions.playOrPause!!.contentDescription)
+ .isEqualTo(context.getString(R.string.controls_media_button_play))
actions.playOrPause!!.action!!.run()
verify(transportControls).play()
assertThat(actions.prevOrCustom).isNotNull()
- assertThat(actions.prevOrCustom!!.contentDescription).isEqualTo(
- context.getString(R.string.controls_media_button_prev))
+ assertThat(actions.prevOrCustom!!.contentDescription)
+ .isEqualTo(context.getString(R.string.controls_media_button_prev))
actions.prevOrCustom!!.action!!.run()
verify(transportControls).skipToPrevious()
assertThat(actions.nextOrCustom).isNotNull()
- assertThat(actions.nextOrCustom!!.contentDescription).isEqualTo(
- context.getString(R.string.controls_media_button_next))
+ assertThat(actions.nextOrCustom!!.contentDescription)
+ .isEqualTo(context.getString(R.string.controls_media_button_next))
actions.nextOrCustom!!.action!!.run()
verify(transportControls).skipToNext()
@@ -837,8 +1042,7 @@ class MediaDataManagerTest : SysuiTestCase() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4", "custom 5")
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY
- val stateBuilder = PlaybackState.Builder()
- .setActions(stateActions)
+ val stateBuilder = PlaybackState.Builder().setActions(stateActions)
customDesc.forEach {
stateBuilder.addCustomAction("action: $it", it, android.R.drawable.ic_media_pause)
}
@@ -850,8 +1054,8 @@ class MediaDataManagerTest : SysuiTestCase() {
val actions = mediaDataCaptor.value!!.semanticActions!!
assertThat(actions.playOrPause).isNotNull()
- assertThat(actions.playOrPause!!.contentDescription).isEqualTo(
- context.getString(R.string.controls_media_button_play))
+ assertThat(actions.playOrPause!!.contentDescription)
+ .isEqualTo(context.getString(R.string.controls_media_button_play))
assertThat(actions.prevOrCustom).isNotNull()
assertThat(actions.prevOrCustom!!.contentDescription).isEqualTo(customDesc[0])
@@ -870,7 +1074,8 @@ class MediaDataManagerTest : SysuiTestCase() {
fun testPlaybackActions_connecting() {
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY
- val stateBuilder = PlaybackState.Builder()
+ val stateBuilder =
+ PlaybackState.Builder()
.setState(PlaybackState.STATE_BUFFERING, 0, 10f)
.setActions(stateActions)
whenever(controller.playbackState).thenReturn(stateBuilder.build())
@@ -881,8 +1086,8 @@ class MediaDataManagerTest : SysuiTestCase() {
val actions = mediaDataCaptor.value!!.semanticActions!!
assertThat(actions.playOrPause).isNotNull()
- assertThat(actions.playOrPause!!.contentDescription).isEqualTo(
- context.getString(R.string.controls_media_button_connecting))
+ assertThat(actions.playOrPause!!.contentDescription)
+ .isEqualTo(context.getString(R.string.controls_media_button_connecting))
}
@Test
@@ -890,15 +1095,15 @@ class MediaDataManagerTest : SysuiTestCase() {
val customDesc = arrayOf("custom 1", "custom 2", "custom 3", "custom 4")
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
val stateActions = PlaybackState.ACTION_PLAY
- val stateBuilder = PlaybackState.Builder()
- .setActions(stateActions)
+ val stateBuilder = PlaybackState.Builder().setActions(stateActions)
customDesc.forEach {
stateBuilder.addCustomAction("action: $it", it, android.R.drawable.ic_media_pause)
}
- val extras = Bundle().apply {
- putBoolean(MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV, true)
- putBoolean(MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT, true)
- }
+ val extras =
+ Bundle().apply {
+ putBoolean(MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV, true)
+ putBoolean(MediaConstants.SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT, true)
+ }
whenever(controller.playbackState).thenReturn(stateBuilder.build())
whenever(controller.extras).thenReturn(extras)
@@ -908,8 +1113,8 @@ class MediaDataManagerTest : SysuiTestCase() {
val actions = mediaDataCaptor.value!!.semanticActions!!
assertThat(actions.playOrPause).isNotNull()
- assertThat(actions.playOrPause!!.contentDescription).isEqualTo(
- context.getString(R.string.controls_media_button_play))
+ assertThat(actions.playOrPause!!.contentDescription)
+ .isEqualTo(context.getString(R.string.controls_media_button_play))
assertThat(actions.prevOrCustom).isNull()
assertThat(actions.nextOrCustom).isNull()
@@ -937,8 +1142,8 @@ class MediaDataManagerTest : SysuiTestCase() {
val actions = mediaDataCaptor.value!!.semanticActions!!
assertThat(actions.playOrPause).isNotNull()
- assertThat(actions.playOrPause!!.contentDescription).isEqualTo(
- context.getString(R.string.controls_media_button_play))
+ assertThat(actions.playOrPause!!.contentDescription)
+ .isEqualTo(context.getString(R.string.controls_media_button_play))
actions.playOrPause!!.action!!.run()
verify(transportControls).play()
}
@@ -951,30 +1156,43 @@ class MediaDataManagerTest : SysuiTestCase() {
// Location is updated to local cast
whenever(controller.metadata).thenReturn(metadataBuilder.build())
- whenever(playbackInfo.playbackType).thenReturn(
- MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE)
+ whenever(playbackInfo.playbackType)
+ .thenReturn(MediaController.PlaybackInfo.PLAYBACK_TYPE_REMOTE)
addNotificationAndLoad()
- verify(logger).logPlaybackLocationChange(anyInt(), eq(PACKAGE_NAME),
- eq(instanceId), eq(MediaData.PLAYBACK_CAST_LOCAL))
+ verify(logger)
+ .logPlaybackLocationChange(
+ anyInt(),
+ eq(PACKAGE_NAME),
+ eq(instanceId),
+ eq(MediaData.PLAYBACK_CAST_LOCAL)
+ )
// update to remote cast
- val rcn = SbnBuilder().run {
- setPkg(SYSTEM_PACKAGE_NAME) // System package
- modifyNotification(context).also {
- it.setSmallIcon(android.R.drawable.ic_media_pause)
- it.setStyle(MediaStyle().apply {
- setMediaSession(session.sessionToken)
- setRemotePlaybackInfo("Remote device", 0, null)
- })
+ val rcn =
+ SbnBuilder().run {
+ setPkg(SYSTEM_PACKAGE_NAME) // System package
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.setStyle(
+ MediaStyle().apply {
+ setMediaSession(session.sessionToken)
+ setRemotePlaybackInfo("Remote device", 0, null)
+ }
+ )
+ }
+ build()
}
- build()
- }
mediaDataManager.onNotificationAdded(KEY, rcn)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(logger).logPlaybackLocationChange(anyInt(), eq(SYSTEM_PACKAGE_NAME),
- eq(instanceId), eq(MediaData.PLAYBACK_CAST_REMOTE))
+ verify(logger)
+ .logPlaybackLocationChange(
+ anyInt(),
+ eq(SYSTEM_PACKAGE_NAME),
+ eq(instanceId),
+ eq(MediaData.PLAYBACK_CAST_REMOTE)
+ )
}
@Test
@@ -984,14 +1202,19 @@ class MediaDataManagerTest : SysuiTestCase() {
verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
// Callback gets an updated state
- val state = PlaybackState.Builder()
- .setState(PlaybackState.STATE_PLAYING, 0L, 1f)
- .build()
+ val state = PlaybackState.Builder().setState(PlaybackState.STATE_PLAYING, 0L, 1f).build()
callbackCaptor.value.invoke(KEY, state)
// Listener is notified of updated state
- verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY),
- capture(mediaDataCaptor), eq(true), eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value.isPlaying).isTrue()
}
@@ -1003,8 +1226,8 @@ class MediaDataManagerTest : SysuiTestCase() {
// No media added with this key
callbackCaptor.value.invoke(KEY, state)
- verify(listener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(), anyInt(),
- anyBoolean())
+ verify(listener, never())
+ .onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(), anyInt(), anyBoolean())
}
@Test
@@ -1022,35 +1245,42 @@ class MediaDataManagerTest : SysuiTestCase() {
// Then no changes are made
callbackCaptor.value.invoke(KEY, state)
- verify(listener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(), anyInt(),
- anyBoolean())
+ verify(listener, never())
+ .onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(), anyInt(), anyBoolean())
}
@Test
fun testPlaybackState_PauseWhenFlagTrue_keyExists_callsListener() {
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(true)
- val state = PlaybackState.Builder()
- .setState(PlaybackState.STATE_PAUSED, 0L, 1f)
- .build()
+ val state = PlaybackState.Builder().setState(PlaybackState.STATE_PAUSED, 0L, 1f).build()
whenever(controller.playbackState).thenReturn(state)
addNotificationAndLoad()
verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
callbackCaptor.value.invoke(KEY, state)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY),
- capture(mediaDataCaptor), eq(true), eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
assertThat(mediaDataCaptor.value.semanticActions).isNotNull()
}
@Test
fun testPlaybackState_PauseStateAfterAddingResumption_keyExists_callsListener() {
- val desc = MediaDescription.Builder().run {
- setTitle(SESSION_TITLE)
- build()
- }
- val state = PlaybackState.Builder()
+ val desc =
+ MediaDescription.Builder().run {
+ setTitle(SESSION_TITLE)
+ build()
+ }
+ val state =
+ PlaybackState.Builder()
.setState(PlaybackState.STATE_PAUSED, 0L, 1f)
.setActions(PlaybackState.ACTION_PLAY_PAUSE)
.build()
@@ -1058,13 +1288,13 @@ class MediaDataManagerTest : SysuiTestCase() {
// Add resumption controls in order to have semantic actions.
// To make sure that they are not null after changing state.
mediaDataManager.addResumptionControls(
- USER_ID,
- desc,
- Runnable {},
- session.sessionToken,
- APP_NAME,
- pendingIntent,
- PACKAGE_NAME
+ USER_ID,
+ desc,
+ Runnable {},
+ session.sessionToken,
+ APP_NAME,
+ pendingIntent,
+ PACKAGE_NAME
)
backgroundExecutor.runAllReady()
foregroundExecutor.runAllReady()
@@ -1073,14 +1303,14 @@ class MediaDataManagerTest : SysuiTestCase() {
callbackCaptor.value.invoke(PACKAGE_NAME, state)
verify(listener)
- .onMediaDataLoaded(
- eq(PACKAGE_NAME),
- eq(PACKAGE_NAME),
- capture(mediaDataCaptor),
- eq(true),
- eq(0),
- eq(false)
- )
+ .onMediaDataLoaded(
+ eq(PACKAGE_NAME),
+ eq(PACKAGE_NAME),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
assertThat(mediaDataCaptor.value.semanticActions).isNotNull()
}
@@ -1088,7 +1318,8 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testPlaybackStateNull_Pause_keyExists_callsListener() {
whenever(controller.playbackState).thenReturn(null)
- val state = PlaybackState.Builder()
+ val state =
+ PlaybackState.Builder()
.setState(PlaybackState.STATE_PAUSED, 0L, 1f)
.setActions(PlaybackState.ACTION_PLAY_PAUSE)
.build()
@@ -1097,20 +1328,32 @@ class MediaDataManagerTest : SysuiTestCase() {
verify(mediaTimeoutListener).stateCallback = capture(callbackCaptor)
callbackCaptor.value.invoke(KEY, state)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY),
- capture(mediaDataCaptor), eq(true), eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(KEY),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
assertThat(mediaDataCaptor.value.semanticActions).isNull()
}
- /**
- * Helper function to add a media notification and capture the resulting MediaData
- */
+ /** Helper function to add a media notification and capture the resulting MediaData */
private fun addNotificationAndLoad() {
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
- verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
- eq(0), eq(false))
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt
index d708aaaa61ac..a45e9d9fcacf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDeviceManagerTest.kt
@@ -113,7 +113,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fakeFgExecutor = FakeExecutor(FakeSystemClock())
fakeBgExecutor = FakeExecutor(FakeSystemClock())
localBluetoothManager = mDependency.injectMockDependency(LocalBluetoothManager::class.java)
- manager = MediaDeviceManager(
+ manager =
+ MediaDeviceManager(
context,
controllerFactory,
lmmFactory,
@@ -124,7 +125,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fakeFgExecutor,
fakeBgExecutor,
dumpster
- )
+ )
manager.addListener(listener)
// Configure mocks.
@@ -138,11 +139,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
// Create a media sesssion and notification for testing.
session = MediaSession(context, SESSION_KEY)
- mediaData = MediaTestUtils.emptyMediaData.copy(
- packageName = PACKAGE,
- token = session.sessionToken)
- whenever(controllerFactory.create(session.sessionToken))
- .thenReturn(controller)
+ mediaData =
+ MediaTestUtils.emptyMediaData.copy(packageName = PACKAGE, token = session.sessionToken)
+ whenever(controllerFactory.create(session.sessionToken)).thenReturn(controller)
setupLeAudioConfiguration(false)
}
@@ -358,7 +357,9 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
val deviceCallback = captureCallback()
// First set a non-null about-to-connect device
deviceCallback.onAboutToConnectDeviceAdded(
- "fakeAddress", "AboutToConnectDeviceName", mock(Drawable::class.java)
+ "fakeAddress",
+ "AboutToConnectDeviceName",
+ mock(Drawable::class.java)
)
// Run and reset the executors and listeners so we only focus on new events.
fakeBgExecutor.runAllReady()
@@ -587,8 +588,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
@Test
fun testRemotePlaybackDeviceOverride() {
whenever(route.name).thenReturn(DEVICE_NAME)
- val deviceData = MediaDeviceData(false, null, REMOTE_DEVICE_NAME, null,
- showBroadcastButton = false)
+ val deviceData =
+ MediaDeviceData(false, null, REMOTE_DEVICE_NAME, null, showBroadcastButton = false)
val mediaDataWithDevice = mediaData.copy(device = deviceData)
// GIVEN media data that already has a device set
@@ -617,8 +618,8 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
val data = captureDeviceData(KEY)
assertThat(data.showBroadcastButton).isTrue()
assertThat(data.enabled).isTrue()
- assertThat(data.name).isEqualTo(context.getString(
- R.string.broadcasting_description_is_broadcasting))
+ assertThat(data.name)
+ .isEqualTo(context.getString(R.string.broadcasting_description_is_broadcasting))
}
@Test
@@ -659,20 +660,21 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
}
fun setupBroadcastCallback(): BluetoothLeBroadcast.Callback {
- val callback: BluetoothLeBroadcast.Callback = object : BluetoothLeBroadcast.Callback {
- override fun onBroadcastStarted(reason: Int, broadcastId: Int) {}
- override fun onBroadcastStartFailed(reason: Int) {}
- override fun onBroadcastStopped(reason: Int, broadcastId: Int) {}
- override fun onBroadcastStopFailed(reason: Int) {}
- override fun onPlaybackStarted(reason: Int, broadcastId: Int) {}
- override fun onPlaybackStopped(reason: Int, broadcastId: Int) {}
- override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {}
- override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {}
- override fun onBroadcastMetadataChanged(
- broadcastId: Int,
- metadata: BluetoothLeBroadcastMetadata
- ) {}
- }
+ val callback: BluetoothLeBroadcast.Callback =
+ object : BluetoothLeBroadcast.Callback {
+ override fun onBroadcastStarted(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastStartFailed(reason: Int) {}
+ override fun onBroadcastStopped(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastStopFailed(reason: Int) {}
+ override fun onPlaybackStarted(reason: Int, broadcastId: Int) {}
+ override fun onPlaybackStopped(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastUpdated(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastUpdateFailed(reason: Int, broadcastId: Int) {}
+ override fun onBroadcastMetadataChanged(
+ broadcastId: Int,
+ metadata: BluetoothLeBroadcastMetadata
+ ) {}
+ }
bluetoothLeBroadcast.registerCallback(fakeFgExecutor, callback)
return callback
@@ -681,7 +683,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fun setupLeAudioConfiguration(isLeAudio: Boolean) {
whenever(localBluetoothManager.profileManager).thenReturn(localBluetoothProfileManager)
whenever(localBluetoothProfileManager.leAudioBroadcastProfile)
- .thenReturn(localBluetoothLeBroadcast)
+ .thenReturn(localBluetoothLeBroadcast)
whenever(localBluetoothLeBroadcast.isEnabled(any())).thenReturn(isLeAudio)
whenever(localBluetoothLeBroadcast.appSourceName).thenReturn(BROADCAST_APP_NAME)
}
@@ -689,7 +691,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() {
fun setupBroadcastPackage(currentName: String) {
whenever(lmm.packageName).thenReturn(PACKAGE)
whenever(packageManager.getApplicationInfo(eq(PACKAGE), anyInt()))
- .thenReturn(applicationInfo)
+ .thenReturn(applicationInfo)
whenever(packageManager.getApplicationLabel(applicationInfo)).thenReturn(currentName)
context.setMockPackageManager(packageManager)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaSessionBasedFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaSessionBasedFilterTest.kt
index ede012eb2213..3099609d42f0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaSessionBasedFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaSessionBasedFilterTest.kt
@@ -23,14 +23,12 @@ import android.media.session.MediaSessionManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
-
import com.android.systemui.SysuiTestCase
import com.android.systemui.media.controls.MediaTestUtils
import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
-
import org.junit.After
import org.junit.Before
import org.junit.Rule
@@ -44,17 +42,15 @@ import org.mockito.Mockito.any
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
+import org.mockito.junit.MockitoJUnit
private const val PACKAGE = "PKG"
private const val KEY = "TEST_KEY"
private const val NOTIF_KEY = "TEST_KEY"
-private val info = MediaTestUtils.emptyMediaData.copy(
- packageName = PACKAGE,
- notificationKey = NOTIF_KEY
-)
+private val info =
+ MediaTestUtils.emptyMediaData.copy(packageName = PACKAGE, notificationKey = NOTIF_KEY)
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -141,10 +137,10 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
// Capture listener
bgExecutor.runAllReady()
- val listenerCaptor = ArgumentCaptor.forClass(
- MediaSessionManager.OnActiveSessionsChangedListener::class.java)
- verify(mediaSessionManager).addOnActiveSessionsChangedListener(
- listenerCaptor.capture(), any())
+ val listenerCaptor =
+ ArgumentCaptor.forClass(MediaSessionManager.OnActiveSessionsChangedListener::class.java)
+ verify(mediaSessionManager)
+ .addOnActiveSessionsChangedListener(listenerCaptor.capture(), any())
sessionListener = listenerCaptor.value
filter.addListener(mediaListener)
@@ -163,8 +159,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
filter.onMediaDataLoaded(KEY, null, mediaData1)
bgExecutor.runAllReady()
fgExecutor.runAllReady()
- verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), eq(0), eq(false))
}
@Test
@@ -186,8 +182,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered
- verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), eq(0), eq(false))
}
@Test
@@ -216,8 +212,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered
- verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), eq(0), eq(false))
}
@Test
@@ -232,15 +228,22 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered
- verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), eq(0), eq(false))
// WHEN a loaded event is received that matches the local session
filter.onMediaDataLoaded(KEY, null, mediaData2)
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is filtered
- verify(mediaListener, never()).onMediaDataLoaded(
- eq(KEY), eq(null), eq(mediaData2), anyBoolean(), anyInt(), anyBoolean())
+ verify(mediaListener, never())
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ eq(mediaData2),
+ anyBoolean(),
+ anyInt(),
+ anyBoolean()
+ )
}
@Test
@@ -256,8 +259,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady()
// THEN the event is not filtered because there isn't a notification for the remote
// session.
- verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), eq(0), eq(false))
}
@Test
@@ -274,16 +277,22 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered
- verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true), eq(0), eq(false))
// WHEN a loaded event is received that matches the local session
filter.onMediaDataLoaded(key2, null, mediaData2)
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is filtered
verify(mediaListener, never())
- .onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean(),
- anyInt(), anyBoolean())
+ .onMediaDataLoaded(
+ eq(key2),
+ eq(null),
+ eq(mediaData2),
+ anyBoolean(),
+ anyInt(),
+ anyBoolean()
+ )
// AND there should be a removed event for key2
verify(mediaListener).onMediaDataRemoved(eq(key2))
}
@@ -302,15 +311,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered
- verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true), eq(0), eq(false))
// WHEN a loaded event is received that matches the remote session
filter.onMediaDataLoaded(key2, null, mediaData2)
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered
- verify(mediaListener).onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), eq(true), eq(0), eq(false))
}
@Test
@@ -326,15 +335,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered
- verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), eq(0), eq(false))
// WHEN a loaded event is received that matches the local session
filter.onMediaDataLoaded(KEY, null, mediaData2)
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered
- verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData2), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData2), eq(true), eq(0), eq(false))
}
@Test
@@ -352,8 +361,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the event is not filtered
- verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true), eq(0), eq(false))
}
@Test
@@ -375,8 +384,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the key migration event is fired
- verify(mediaListener).onMediaDataLoaded(eq(key2), eq(key1), eq(mediaData2), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(key2), eq(key1), eq(mediaData2), eq(true), eq(0), eq(false))
}
@Test
@@ -406,14 +415,20 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady()
// THEN the key migration event is filtered
verify(mediaListener, never())
- .onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean(),
- anyInt(), anyBoolean())
+ .onMediaDataLoaded(
+ eq(key2),
+ eq(null),
+ eq(mediaData2),
+ anyBoolean(),
+ anyInt(),
+ anyBoolean()
+ )
// WHEN a loaded event is received that matches the remote session
filter.onMediaDataLoaded(key2, null, mediaData1)
bgExecutor.runAllReady()
fgExecutor.runAllReady()
// THEN the key migration event is fired
- verify(mediaListener).onMediaDataLoaded(eq(key2), eq(null), eq(mediaData1), eq(true),
- eq(0), eq(false))
+ verify(mediaListener)
+ .onMediaDataLoaded(eq(key2), eq(null), eq(mediaData1), eq(true), eq(0), eq(false))
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListenerTest.kt
index 1408ed07d808..344dffafb448 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaTimeoutListenerTest.kt
@@ -44,11 +44,11 @@ import org.mockito.ArgumentMatchers.anyString
import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito
-import org.mockito.Mockito.`when`
import org.mockito.Mockito.clearInvocations
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.junit.MockitoJUnit
private const val KEY = "KEY"
@@ -73,7 +73,8 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Mock private lateinit var timeoutCallback: (String, Boolean) -> Unit
@Mock private lateinit var stateCallback: (String, PlaybackState) -> Unit
@Captor private lateinit var mediaCallbackCaptor: ArgumentCaptor<MediaController.Callback>
- @Captor private lateinit var dozingCallbackCaptor:
+ @Captor
+ private lateinit var dozingCallbackCaptor:
ArgumentCaptor<StatusBarStateController.StateListener>
@JvmField @Rule val mockito = MockitoJUnit.rule()
private lateinit var metadataBuilder: MediaMetadata.Builder
@@ -88,36 +89,41 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
fun setup() {
`when`(mediaControllerFactory.create(any())).thenReturn(mediaController)
executor = FakeExecutor(clock)
- mediaTimeoutListener = MediaTimeoutListener(
- mediaControllerFactory,
- executor,
- logger,
- statusBarStateController,
- clock
- )
+ mediaTimeoutListener =
+ MediaTimeoutListener(
+ mediaControllerFactory,
+ executor,
+ logger,
+ statusBarStateController,
+ clock
+ )
mediaTimeoutListener.timeoutCallback = timeoutCallback
mediaTimeoutListener.stateCallback = stateCallback
// Create a media session and notification for testing.
- metadataBuilder = MediaMetadata.Builder().apply {
- putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
- putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
- }
- playbackBuilder = PlaybackState.Builder().apply {
- setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
- setActions(PlaybackState.ACTION_PLAY)
- }
- session = MediaSession(context, SESSION_KEY).apply {
- setMetadata(metadataBuilder.build())
- setPlaybackState(playbackBuilder.build())
- }
+ metadataBuilder =
+ MediaMetadata.Builder().apply {
+ putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
+ putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
+ }
+ playbackBuilder =
+ PlaybackState.Builder().apply {
+ setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
+ setActions(PlaybackState.ACTION_PLAY)
+ }
+ session =
+ MediaSession(context, SESSION_KEY).apply {
+ setMetadata(metadataBuilder.build())
+ setPlaybackState(playbackBuilder.build())
+ }
session.setActive(true)
- mediaData = MediaTestUtils.emptyMediaData.copy(
- app = PACKAGE,
- packageName = PACKAGE,
- token = session.sessionToken
- )
+ mediaData =
+ MediaTestUtils.emptyMediaData.copy(
+ app = PACKAGE,
+ packageName = PACKAGE,
+ token = session.sessionToken
+ )
resumeData = mediaData.copy(token = null, active = false, resumption = true)
}
@@ -215,8 +221,9 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
// Assuming we're registered
testOnMediaDataLoaded_registersPlaybackListener()
- mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
- .setState(PlaybackState.STATE_PAUSED, 0L, 0f).build())
+ mediaCallbackCaptor.value.onPlaybackStateChanged(
+ PlaybackState.Builder().setState(PlaybackState.STATE_PAUSED, 0L, 0f).build()
+ )
assertThat(executor.numPending()).isEqualTo(1)
assertThat(executor.advanceClockToNext()).isEqualTo(PAUSED_MEDIA_TIMEOUT)
}
@@ -226,8 +233,9 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
// Assuming we have a pending timeout
testOnPlaybackStateChanged_schedulesTimeout_whenPaused()
- mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
- .setState(PlaybackState.STATE_PLAYING, 0L, 0f).build())
+ mediaCallbackCaptor.value.onPlaybackStateChanged(
+ PlaybackState.Builder().setState(PlaybackState.STATE_PLAYING, 0L, 0f).build()
+ )
assertThat(executor.numPending()).isEqualTo(0)
verify(logger).logTimeoutCancelled(eq(KEY), any())
}
@@ -237,8 +245,9 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
// Assuming we have a pending timeout
testOnPlaybackStateChanged_schedulesTimeout_whenPaused()
- mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
- .setState(PlaybackState.STATE_STOPPED, 0L, 0f).build())
+ mediaCallbackCaptor.value.onPlaybackStateChanged(
+ PlaybackState.Builder().setState(PlaybackState.STATE_STOPPED, 0L, 0f).build()
+ )
assertThat(executor.numPending()).isEqualTo(1)
}
@@ -332,9 +341,8 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testOnMediaDataLoaded_pausedToResume_updatesTimeout() {
// WHEN regular media is paused
- val pausedState = PlaybackState.Builder()
- .setState(PlaybackState.STATE_PAUSED, 0L, 0f)
- .build()
+ val pausedState =
+ PlaybackState.Builder().setState(PlaybackState.STATE_PAUSED, 0L, 0f).build()
`when`(mediaController.playbackState).thenReturn(pausedState)
mediaTimeoutListener.onMediaDataLoaded(KEY, null, mediaData)
assertThat(executor.numPending()).isEqualTo(1)
@@ -365,9 +373,8 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
mediaTimeoutListener.onMediaDataLoaded(PACKAGE, null, resumeData)
// AND that media is resumed
- val playingState = PlaybackState.Builder()
- .setState(PlaybackState.STATE_PAUSED, 0L, 0f)
- .build()
+ val playingState =
+ PlaybackState.Builder().setState(PlaybackState.STATE_PAUSED, 0L, 0f).build()
`when`(mediaController.playbackState).thenReturn(playingState)
mediaTimeoutListener.onMediaDataLoaded(KEY, PACKAGE, mediaData)
@@ -389,15 +396,11 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testOnMediaDataLoaded_playbackActionsChanged_noCallback() {
// Load media data once
- val pausedState = PlaybackState.Builder()
- .setActions(PlaybackState.ACTION_PAUSE)
- .build()
+ val pausedState = PlaybackState.Builder().setActions(PlaybackState.ACTION_PAUSE).build()
loadMediaDataWithPlaybackState(pausedState)
// When media data is loaded again, with different actions
- val playingState = PlaybackState.Builder()
- .setActions(PlaybackState.ACTION_PLAY)
- .build()
+ val playingState = PlaybackState.Builder().setActions(PlaybackState.ACTION_PLAY).build()
loadMediaDataWithPlaybackState(playingState)
// Then the callback is not invoked
@@ -407,15 +410,11 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testOnPlaybackStateChanged_playbackActionsChanged_sendsCallback() {
// Load media data once
- val pausedState = PlaybackState.Builder()
- .setActions(PlaybackState.ACTION_PAUSE)
- .build()
+ val pausedState = PlaybackState.Builder().setActions(PlaybackState.ACTION_PAUSE).build()
loadMediaDataWithPlaybackState(pausedState)
// When the playback state changes, and has different actions
- val playingState = PlaybackState.Builder()
- .setActions(PlaybackState.ACTION_PLAY)
- .build()
+ val playingState = PlaybackState.Builder().setActions(PlaybackState.ACTION_PLAY).build()
mediaCallbackCaptor.value.onPlaybackStateChanged(playingState)
// Then the callback is invoked
@@ -424,24 +423,30 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testOnPlaybackStateChanged_differentCustomActions_sendsCallback() {
- val customOne = PlaybackState.CustomAction.Builder(
+ val customOne =
+ PlaybackState.CustomAction.Builder(
"ACTION_1",
"custom action 1",
- android.R.drawable.ic_media_ff)
+ android.R.drawable.ic_media_ff
+ )
.build()
- val pausedState = PlaybackState.Builder()
+ val pausedState =
+ PlaybackState.Builder()
.setActions(PlaybackState.ACTION_PAUSE)
.addCustomAction(customOne)
.build()
loadMediaDataWithPlaybackState(pausedState)
// When the playback state actions change
- val customTwo = PlaybackState.CustomAction.Builder(
- "ACTION_2",
- "custom action 2",
- android.R.drawable.ic_media_rew)
+ val customTwo =
+ PlaybackState.CustomAction.Builder(
+ "ACTION_2",
+ "custom action 2",
+ android.R.drawable.ic_media_rew
+ )
.build()
- val pausedStateTwoActions = PlaybackState.Builder()
+ val pausedStateTwoActions =
+ PlaybackState.Builder()
.setActions(PlaybackState.ACTION_PAUSE)
.addCustomAction(customOne)
.addCustomAction(customTwo)
@@ -454,9 +459,7 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testOnPlaybackStateChanged_sameActions_noCallback() {
- val stateWithActions = PlaybackState.Builder()
- .setActions(PlaybackState.ACTION_PLAY)
- .build()
+ val stateWithActions = PlaybackState.Builder().setActions(PlaybackState.ACTION_PLAY).build()
loadMediaDataWithPlaybackState(stateWithActions)
// When the playback state updates with the same actions
@@ -470,18 +473,20 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
fun testOnPlaybackStateChanged_sameCustomActions_noCallback() {
val actionName = "custom action"
val actionIcon = android.R.drawable.ic_media_ff
- val customOne = PlaybackState.CustomAction.Builder(actionName, actionName, actionIcon)
- .build()
- val stateOne = PlaybackState.Builder()
+ val customOne =
+ PlaybackState.CustomAction.Builder(actionName, actionName, actionIcon).build()
+ val stateOne =
+ PlaybackState.Builder()
.setActions(PlaybackState.ACTION_PAUSE)
.addCustomAction(customOne)
.build()
loadMediaDataWithPlaybackState(stateOne)
// When the playback state is updated, but has the same actions
- val customTwo = PlaybackState.CustomAction.Builder(actionName, actionName, actionIcon)
- .build()
- val stateTwo = PlaybackState.Builder()
+ val customTwo =
+ PlaybackState.CustomAction.Builder(actionName, actionName, actionIcon).build()
+ val stateTwo =
+ PlaybackState.Builder()
.setActions(PlaybackState.ACTION_PAUSE)
.addCustomAction(customTwo)
.build()
@@ -494,15 +499,13 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testOnMediaDataLoaded_isPlayingChanged_noCallback() {
// Load media data in paused state
- val pausedState = PlaybackState.Builder()
- .setState(PlaybackState.STATE_PAUSED, 0L, 0f)
- .build()
+ val pausedState =
+ PlaybackState.Builder().setState(PlaybackState.STATE_PAUSED, 0L, 0f).build()
loadMediaDataWithPlaybackState(pausedState)
// When media data is loaded again but playing
- val playingState = PlaybackState.Builder()
- .setState(PlaybackState.STATE_PLAYING, 0L, 1f)
- .build()
+ val playingState =
+ PlaybackState.Builder().setState(PlaybackState.STATE_PLAYING, 0L, 1f).build()
loadMediaDataWithPlaybackState(playingState)
// Then the callback is not invoked
@@ -512,15 +515,13 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testOnPlaybackStateChanged_isPlayingChanged_sendsCallback() {
// Load media data in paused state
- val pausedState = PlaybackState.Builder()
- .setState(PlaybackState.STATE_PAUSED, 0L, 0f)
- .build()
+ val pausedState =
+ PlaybackState.Builder().setState(PlaybackState.STATE_PAUSED, 0L, 0f).build()
loadMediaDataWithPlaybackState(pausedState)
// When the playback state changes to playing
- val playingState = PlaybackState.Builder()
- .setState(PlaybackState.STATE_PLAYING, 0L, 1f)
- .build()
+ val playingState =
+ PlaybackState.Builder().setState(PlaybackState.STATE_PLAYING, 0L, 1f).build()
mediaCallbackCaptor.value.onPlaybackStateChanged(playingState)
// Then the callback is invoked
@@ -530,15 +531,13 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
@Test
fun testOnPlaybackStateChanged_isPlayingSame_noCallback() {
// Load media data in paused state
- val pausedState = PlaybackState.Builder()
- .setState(PlaybackState.STATE_PAUSED, 0L, 0f)
- .build()
+ val pausedState =
+ PlaybackState.Builder().setState(PlaybackState.STATE_PAUSED, 0L, 0f).build()
loadMediaDataWithPlaybackState(pausedState)
// When the playback state is updated, but still not playing
- val playingState = PlaybackState.Builder()
- .setState(PlaybackState.STATE_STOPPED, 0L, 0f)
- .build()
+ val playingState =
+ PlaybackState.Builder().setState(PlaybackState.STATE_STOPPED, 0L, 0f).build()
mediaCallbackCaptor.value.onPlaybackStateChanged(playingState)
// Then the callback is not invoked
@@ -549,8 +548,9 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
fun testTimeoutCallback_dozedPastTimeout_invokedOnWakeup() {
// When paused media is loaded
testOnMediaDataLoaded_registersPlaybackListener()
- mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
- .setState(PlaybackState.STATE_PAUSED, 0L, 0f).build())
+ mediaCallbackCaptor.value.onPlaybackStateChanged(
+ PlaybackState.Builder().setState(PlaybackState.STATE_PAUSED, 0L, 0f).build()
+ )
verify(statusBarStateController).addCallback(capture(dozingCallbackCaptor))
// And we doze past the scheduled timeout
@@ -574,8 +574,9 @@ class MediaTimeoutListenerTest : SysuiTestCase() {
val time = clock.currentTimeMillis()
clock.setElapsedRealtime(time)
testOnMediaDataLoaded_registersPlaybackListener()
- mediaCallbackCaptor.value.onPlaybackStateChanged(PlaybackState.Builder()
- .setState(PlaybackState.STATE_PAUSED, 0L, 0f).build())
+ mediaCallbackCaptor.value.onPlaybackStateChanged(
+ PlaybackState.Builder().setState(PlaybackState.STATE_PAUSED, 0L, 0f).build()
+ )
verify(statusBarStateController).addCallback(capture(dozingCallbackCaptor))
// And we doze, but not past the scheduled timeout
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
index 91938a646b94..84fdfd78e9fc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
@@ -36,13 +36,13 @@ import com.android.systemui.dump.DumpManager
import com.android.systemui.media.controls.MediaTestUtils
import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.models.player.MediaDeviceData
-import com.android.systemui.media.controls.pipeline.RESUME_MEDIA_TIMEOUT
import com.android.systemui.media.controls.pipeline.MediaDataManager
+import com.android.systemui.media.controls.pipeline.RESUME_MEDIA_TIMEOUT
import com.android.systemui.tuner.TunerService
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
-import org.junit.After
import com.google.common.truth.Truth.assertThat
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -68,7 +68,9 @@ private const val MEDIA_PREFERENCES = "media_control_prefs"
private const val RESUME_COMPONENTS = "package1/class1:package2/class2:package3/class3"
private fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+
private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
+
private fun <T> any(): T = Mockito.any<T>()
@SmallTest
@@ -98,26 +100,32 @@ class MediaResumeListenerTest : SysuiTestCase() {
private lateinit var resumeListener: MediaResumeListener
private val clock = FakeSystemClock()
- private var originalQsSetting = Settings.Global.getInt(context.contentResolver,
- Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1)
- private var originalResumeSetting = Settings.Secure.getInt(context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RESUME, 0)
+ private var originalQsSetting =
+ Settings.Global.getInt(
+ context.contentResolver,
+ Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS,
+ 1
+ )
+ private var originalResumeSetting =
+ Settings.Secure.getInt(context.contentResolver, Settings.Secure.MEDIA_CONTROLS_RESUME, 0)
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- Settings.Global.putInt(context.contentResolver,
- Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1)
- Settings.Secure.putInt(context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RESUME, 1)
+ Settings.Global.putInt(
+ context.contentResolver,
+ Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS,
+ 1
+ )
+ Settings.Secure.putInt(context.contentResolver, Settings.Secure.MEDIA_CONTROLS_RESUME, 1)
whenever(resumeBrowserFactory.create(capture(callbackCaptor), any()))
- .thenReturn(resumeBrowser)
+ .thenReturn(resumeBrowser)
// resume components are stored in sharedpreferences
whenever(mockContext.getSharedPreferences(eq(MEDIA_PREFERENCES), anyInt()))
- .thenReturn(sharedPrefs)
+ .thenReturn(sharedPrefs)
whenever(sharedPrefs.getString(any(), any())).thenReturn(RESUME_COMPONENTS)
whenever(sharedPrefs.edit()).thenReturn(sharedPrefsEditor)
whenever(sharedPrefsEditor.putString(any(), any())).thenReturn(sharedPrefsEditor)
@@ -125,36 +133,59 @@ class MediaResumeListenerTest : SysuiTestCase() {
whenever(mockContext.contentResolver).thenReturn(context.contentResolver)
executor = FakeExecutor(clock)
- resumeListener = MediaResumeListener(mockContext, broadcastDispatcher, executor,
- tunerService, resumeBrowserFactory, dumpManager, clock)
+ resumeListener =
+ MediaResumeListener(
+ mockContext,
+ broadcastDispatcher,
+ executor,
+ tunerService,
+ resumeBrowserFactory,
+ dumpManager,
+ clock
+ )
resumeListener.setManager(mediaDataManager)
mediaDataManager.addListener(resumeListener)
- data = MediaTestUtils.emptyMediaData.copy(
+ data =
+ MediaTestUtils.emptyMediaData.copy(
song = TITLE,
packageName = PACKAGE_NAME,
- token = token)
+ token = token
+ )
}
@After
fun tearDown() {
- Settings.Global.putInt(context.contentResolver,
- Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS, originalQsSetting)
- Settings.Secure.putInt(context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RESUME, originalResumeSetting)
+ Settings.Global.putInt(
+ context.contentResolver,
+ Settings.Global.SHOW_MEDIA_ON_QUICK_SETTINGS,
+ originalQsSetting
+ )
+ Settings.Secure.putInt(
+ context.contentResolver,
+ Settings.Secure.MEDIA_CONTROLS_RESUME,
+ originalResumeSetting
+ )
}
@Test
fun testWhenNoResumption_doesNothing() {
- Settings.Secure.putInt(context.contentResolver,
- Settings.Secure.MEDIA_CONTROLS_RESUME, 0)
+ Settings.Secure.putInt(context.contentResolver, Settings.Secure.MEDIA_CONTROLS_RESUME, 0)
// When listener is created, we do NOT register a user change listener
- val listener = MediaResumeListener(context, broadcastDispatcher, executor, tunerService,
- resumeBrowserFactory, dumpManager, clock)
+ val listener =
+ MediaResumeListener(
+ context,
+ broadcastDispatcher,
+ executor,
+ tunerService,
+ resumeBrowserFactory,
+ dumpManager,
+ clock
+ )
listener.setManager(mediaDataManager)
- verify(broadcastDispatcher, never()).registerReceiver(eq(listener.userChangeReceiver),
- any(), any(), any(), anyInt(), any())
+ verify(broadcastDispatcher, never())
+ .registerReceiver(eq(listener.userChangeReceiver), any(), any(), any(), anyInt(), any())
// When data is loaded, we do NOT execute or update anything
listener.onMediaDataLoaded(KEY, OLD_KEY, data)
@@ -175,9 +206,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
fun testOnLoad_checksForResume_badService() {
setUpMbsWithValidResolveInfo()
- whenever(resumeBrowser.testConnection()).thenAnswer {
- callbackCaptor.value.onError()
- }
+ whenever(resumeBrowser.testConnection()).thenAnswer { callbackCaptor.value.onError() }
// When media data is loaded that has not been checked yet, and does not have a MBS
resumeListener.onMediaDataLoaded(KEY, null, data)
@@ -231,7 +260,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
// But we do not tell it to add new controls
verify(mediaDataManager, never())
- .addResumptionControls(anyInt(), any(), any(), any(), any(), any(), any())
+ .addResumptionControls(anyInt(), any(), any(), any(), any(), any(), any())
}
@Test
@@ -258,8 +287,15 @@ class MediaResumeListenerTest : SysuiTestCase() {
// Make sure broadcast receiver is registered
resumeListener.setManager(mediaDataManager)
- verify(broadcastDispatcher).registerReceiver(eq(resumeListener.userChangeReceiver),
- any(), any(), any(), anyInt(), any())
+ verify(broadcastDispatcher)
+ .registerReceiver(
+ eq(resumeListener.userChangeReceiver),
+ any(),
+ any(),
+ any(),
+ anyInt(),
+ any()
+ )
// When we get an unlock event
val intent = Intent(Intent.ACTION_USER_UNLOCKED)
@@ -269,8 +305,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
verify(resumeBrowser, times(3)).findRecentMedia()
// Then since the mock service found media, the manager should be informed
- verify(mediaDataManager, times(3)).addResumptionControls(anyInt(),
- any(), any(), any(), any(), any(), eq(PACKAGE_NAME))
+ verify(mediaDataManager, times(3))
+ .addResumptionControls(anyInt(), any(), any(), any(), any(), any(), eq(PACKAGE_NAME))
}
@Test
@@ -309,12 +345,14 @@ class MediaResumeListenerTest : SysuiTestCase() {
// Then we save an update with the current time
verify(sharedPrefsEditor).putString(any(), (capture(componentCaptor)))
- componentCaptor.value.split(ResumeMediaBrowser.DELIMITER.toRegex())
- .dropLastWhile { it.isEmpty() }.forEach {
- val result = it.split("/")
- assertThat(result.size).isEqualTo(3)
- assertThat(result[2].toLong()).isEqualTo(currentTime)
- }
+ componentCaptor.value
+ .split(ResumeMediaBrowser.DELIMITER.toRegex())
+ .dropLastWhile { it.isEmpty() }
+ .forEach {
+ val result = it.split("/")
+ assertThat(result.size).isEqualTo(3)
+ assertThat(result[2].toLong()).isEqualTo(currentTime)
+ }
verify(sharedPrefsEditor, times(1)).apply()
}
@@ -333,8 +371,16 @@ class MediaResumeListenerTest : SysuiTestCase() {
val lastPlayed = clock.currentTimeMillis()
val componentsString = "$PACKAGE_NAME/$CLASS_NAME/$lastPlayed:"
whenever(sharedPrefs.getString(any(), any())).thenReturn(componentsString)
- val resumeListener = MediaResumeListener(mockContext, broadcastDispatcher, executor,
- tunerService, resumeBrowserFactory, dumpManager, clock)
+ val resumeListener =
+ MediaResumeListener(
+ mockContext,
+ broadcastDispatcher,
+ executor,
+ tunerService,
+ resumeBrowserFactory,
+ dumpManager,
+ clock
+ )
resumeListener.setManager(mediaDataManager)
mediaDataManager.addListener(resumeListener)
@@ -344,8 +390,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
// We add its resume controls
verify(resumeBrowser, times(1)).findRecentMedia()
- verify(mediaDataManager, times(1)).addResumptionControls(anyInt(),
- any(), any(), any(), any(), any(), eq(PACKAGE_NAME))
+ verify(mediaDataManager, times(1))
+ .addResumptionControls(anyInt(), any(), any(), any(), any(), any(), eq(PACKAGE_NAME))
}
@Test
@@ -354,8 +400,16 @@ class MediaResumeListenerTest : SysuiTestCase() {
val lastPlayed = clock.currentTimeMillis() - RESUME_MEDIA_TIMEOUT - 100
val componentsString = "$PACKAGE_NAME/$CLASS_NAME/$lastPlayed:"
whenever(sharedPrefs.getString(any(), any())).thenReturn(componentsString)
- val resumeListener = MediaResumeListener(mockContext, broadcastDispatcher, executor,
- tunerService, resumeBrowserFactory, dumpManager, clock)
+ val resumeListener =
+ MediaResumeListener(
+ mockContext,
+ broadcastDispatcher,
+ executor,
+ tunerService,
+ resumeBrowserFactory,
+ dumpManager,
+ clock
+ )
resumeListener.setManager(mediaDataManager)
mediaDataManager.addListener(resumeListener)
@@ -365,8 +419,8 @@ class MediaResumeListenerTest : SysuiTestCase() {
// We do not try to add resume controls
verify(resumeBrowser, times(0)).findRecentMedia()
- verify(mediaDataManager, times(0)).addResumptionControls(anyInt(),
- any(), any(), any(), any(), any(), any())
+ verify(mediaDataManager, times(0))
+ .addResumptionControls(anyInt(), any(), any(), any(), any(), any(), any())
}
@Test
@@ -385,8 +439,16 @@ class MediaResumeListenerTest : SysuiTestCase() {
val lastPlayed = currentTime - 1000
val componentsString = "$PACKAGE_NAME/$CLASS_NAME/$lastPlayed:"
whenever(sharedPrefs.getString(any(), any())).thenReturn(componentsString)
- val resumeListener = MediaResumeListener(mockContext, broadcastDispatcher, executor,
- tunerService, resumeBrowserFactory, dumpManager, clock)
+ val resumeListener =
+ MediaResumeListener(
+ mockContext,
+ broadcastDispatcher,
+ executor,
+ tunerService,
+ resumeBrowserFactory,
+ dumpManager,
+ clock
+ )
resumeListener.setManager(mediaDataManager)
mediaDataManager.addListener(resumeListener)
@@ -396,12 +458,14 @@ class MediaResumeListenerTest : SysuiTestCase() {
// Then we store the new lastPlayed time
verify(sharedPrefsEditor).putString(any(), (capture(componentCaptor)))
- componentCaptor.value.split(ResumeMediaBrowser.DELIMITER.toRegex())
- .dropLastWhile { it.isEmpty() }.forEach {
- val result = it.split("/")
- assertThat(result.size).isEqualTo(3)
- assertThat(result[2].toLong()).isEqualTo(currentTime)
- }
+ componentCaptor.value
+ .split(ResumeMediaBrowser.DELIMITER.toRegex())
+ .dropLastWhile { it.isEmpty() }
+ .forEach {
+ val result = it.split("/")
+ assertThat(result.size).isEqualTo(3)
+ assertThat(result[2].toLong()).isEqualTo(currentTime)
+ }
verify(sharedPrefsEditor, times(1)).apply()
}
@@ -422,9 +486,7 @@ class MediaResumeListenerTest : SysuiTestCase() {
setUpMbsWithValidResolveInfo()
// Set up mocks to return with an error
- whenever(resumeBrowser.testConnection()).thenAnswer {
- callbackCaptor.value.onError()
- }
+ whenever(resumeBrowser.testConnection()).thenAnswer { callbackCaptor.value.onError() }
resumeListener.onMediaDataLoaded(key = KEY, oldKey = null, data)
executor.runAllReady()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserTest.kt
index c490ae32e014..a04cfd46588b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/ResumeMediaBrowserTest.kt
@@ -37,8 +37,8 @@ import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
private const val PACKAGE_NAME = "package"
private const val CLASS_NAME = "class"
@@ -47,7 +47,9 @@ private const val MEDIA_ID = "media ID"
private const val ROOT = "media browser root"
private fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
+
private fun <T> eq(value: T): T = Mockito.eq(value) ?: value
+
private fun <T> any(): T = Mockito.any<T>()
@SmallTest
@@ -57,10 +59,8 @@ public class ResumeMediaBrowserTest : SysuiTestCase() {
private lateinit var resumeBrowser: TestableResumeMediaBrowser
private val component = ComponentName(PACKAGE_NAME, CLASS_NAME)
- private val description = MediaDescription.Builder()
- .setTitle(TITLE)
- .setMediaId(MEDIA_ID)
- .build()
+ private val description =
+ MediaDescription.Builder().setTitle(TITLE).setMediaId(MEDIA_ID).build()
@Mock lateinit var callback: ResumeMediaBrowser.Callback
@Mock lateinit var listener: MediaResumeListener
@@ -81,19 +81,20 @@ public class ResumeMediaBrowserTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
whenever(browserFactory.create(any(), capture(connectionCallback), any()))
- .thenReturn(browser)
+ .thenReturn(browser)
whenever(mediaController.transportControls).thenReturn(transportControls)
whenever(mediaController.sessionToken).thenReturn(token)
- resumeBrowser = TestableResumeMediaBrowser(
- context,
- callback,
- component,
- browserFactory,
- logger,
- mediaController
- )
+ resumeBrowser =
+ TestableResumeMediaBrowser(
+ context,
+ callback,
+ component,
+ browserFactory,
+ logger,
+ mediaController
+ )
}
@Test
@@ -329,30 +330,20 @@ public class ResumeMediaBrowserTest : SysuiTestCase() {
verify(oldBrowser).disconnect()
}
- /**
- * Helper function to mock a failed connection
- */
+ /** Helper function to mock a failed connection */
private fun setupBrowserFailed() {
- whenever(browser.connect()).thenAnswer {
- connectionCallback.value.onConnectionFailed()
- }
+ whenever(browser.connect()).thenAnswer { connectionCallback.value.onConnectionFailed() }
}
- /**
- * Helper function to mock a successful connection only
- */
+ /** Helper function to mock a successful connection only */
private fun setupBrowserConnection() {
- whenever(browser.connect()).thenAnswer {
- connectionCallback.value.onConnected()
- }
+ whenever(browser.connect()).thenAnswer { connectionCallback.value.onConnected() }
whenever(browser.isConnected()).thenReturn(true)
whenever(browser.getRoot()).thenReturn(ROOT)
whenever(browser.sessionToken).thenReturn(token)
}
- /**
- * Helper function to mock a successful connection, but no media results
- */
+ /** Helper function to mock a successful connection, but no media results */
private fun setupBrowserConnectionNoResults() {
setupBrowserConnection()
whenever(browser.subscribe(any(), capture(subscriptionCallback))).thenAnswer {
@@ -360,9 +351,7 @@ public class ResumeMediaBrowserTest : SysuiTestCase() {
}
}
- /**
- * Helper function to mock a successful connection, but no playable results
- */
+ /** Helper function to mock a successful connection, but no playable results */
private fun setupBrowserConnectionNotPlayable() {
setupBrowserConnection()
@@ -373,9 +362,7 @@ public class ResumeMediaBrowserTest : SysuiTestCase() {
}
}
- /**
- * Helper function to mock a successful connection with playable media
- */
+ /** Helper function to mock a successful connection with playable media */
private fun setupBrowserConnectionValidMedia() {
setupBrowserConnection()
@@ -387,9 +374,7 @@ public class ResumeMediaBrowserTest : SysuiTestCase() {
}
}
- /**
- * Override so media controller use is testable
- */
+ /** Override so media controller use is testable */
private class TestableResumeMediaBrowser(
context: Context,
callback: Callback,
@@ -403,4 +388,4 @@ public class ResumeMediaBrowserTest : SysuiTestCase() {
return fakeController
}
}
-} \ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/AnimationBindHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/AnimationBindHandlerTest.kt
index a9cae0d8d91f..99f56b16ab8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/AnimationBindHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/AnimationBindHandlerTest.kt
@@ -16,24 +16,24 @@
package com.android.systemui.media.controls.ui
-import org.mockito.Mockito.`when` as whenever
import android.graphics.drawable.Animatable2
import android.graphics.drawable.Drawable
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import com.android.systemui.SysuiTestCase
-import junit.framework.Assert.assertTrue
import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.times
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@SmallTest
@@ -56,8 +56,7 @@ class AnimationBindHandlerTest : SysuiTestCase() {
handler = AnimationBindHandler()
}
- @After
- fun tearDown() {}
+ @After fun tearDown() {}
@Test
fun registerNoAnimations_executeCallbackImmediately() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/ColorSchemeTransitionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/ColorSchemeTransitionTest.kt
index ece883a39c29..5bb74e5a31f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/ColorSchemeTransitionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/ColorSchemeTransitionTest.kt
@@ -69,21 +69,18 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
animatingColorTransitionFactory = { _, _, _ -> mockAnimatingTransition }
whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR)
- colorSchemeTransition = ColorSchemeTransition(
- context, mediaViewHolder, animatingColorTransitionFactory
- )
-
- colorTransition = object : AnimatingColorTransition(
- DEFAULT_COLOR, extractColor, applyColor
- ) {
- override fun buildAnimator(): ValueAnimator {
- return valueAnimator
+ colorSchemeTransition =
+ ColorSchemeTransition(context, mediaViewHolder, animatingColorTransitionFactory)
+
+ colorTransition =
+ object : AnimatingColorTransition(DEFAULT_COLOR, extractColor, applyColor) {
+ override fun buildAnimator(): ValueAnimator {
+ return valueAnimator
+ }
}
- }
}
- @After
- fun tearDown() {}
+ @After fun tearDown() {}
@Test
fun testColorTransition_nullColorScheme_keepsDefault() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
index 7f007f14bf0c..20260069c943 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/KeyguardMediaControllerTest.kt
@@ -48,17 +48,12 @@ import org.mockito.junit.MockitoJUnit
@TestableLooper.RunWithLooper
class KeyguardMediaControllerTest : SysuiTestCase() {
- @Mock
- private lateinit var mediaHost: MediaHost
- @Mock
- private lateinit var bypassController: KeyguardBypassController
- @Mock
- private lateinit var statusBarStateController: SysuiStatusBarStateController
- @Mock
- private lateinit var configurationController: ConfigurationController
-
- @JvmField @Rule
- val mockito = MockitoJUnit.rule()
+ @Mock private lateinit var mediaHost: MediaHost
+ @Mock private lateinit var bypassController: KeyguardBypassController
+ @Mock private lateinit var statusBarStateController: SysuiStatusBarStateController
+ @Mock private lateinit var configurationController: ConfigurationController
+
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
private val mediaContainerView: MediaContainerView = MediaContainerView(context, null)
private val hostView = UniqueObjectHostView(context)
@@ -76,15 +71,16 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
hostView.layoutParams = FrameLayout.LayoutParams(100, 100)
testableLooper = TestableLooper.get(this)
fakeHandler = FakeHandler(testableLooper.looper)
- keyguardMediaController = KeyguardMediaController(
- mediaHost,
- bypassController,
- statusBarStateController,
- context,
- settings,
- fakeHandler,
- configurationController,
- )
+ keyguardMediaController =
+ KeyguardMediaController(
+ mediaHost,
+ bypassController,
+ statusBarStateController,
+ context,
+ settings,
+ fakeHandler,
+ configurationController,
+ )
keyguardMediaController.attachSinglePaneContainer(mediaContainerView)
keyguardMediaController.useSplitShade = false
}
@@ -153,8 +149,10 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
keyguardMediaController.useSplitShade = true
- assertTrue("HostView wasn't attached to the split pane container",
- splitShadeContainer.childCount == 1)
+ assertTrue(
+ "HostView wasn't attached to the split pane container",
+ splitShadeContainer.childCount == 1
+ )
}
@Test
@@ -162,8 +160,10 @@ class KeyguardMediaControllerTest : SysuiTestCase() {
val splitShadeContainer = FrameLayout(context)
keyguardMediaController.attachSplitShadeContainer(splitShadeContainer)
- assertTrue("HostView wasn't attached to the single pane container",
- mediaContainerView.childCount == 1)
+ assertTrue(
+ "HostView wasn't attached to the single pane container",
+ mediaContainerView.childCount == 1
+ )
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
index f170ef27968f..c8e8943689c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt
@@ -93,22 +93,23 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- mediaCarouselController = MediaCarouselController(
- context,
- mediaControlPanelFactory,
- visualStabilityProvider,
- mediaHostStatesManager,
- activityStarter,
- clock,
- executor,
- mediaDataManager,
- configurationController,
- falsingCollector,
- falsingManager,
- dumpManager,
- logger,
- debugLogger
- )
+ mediaCarouselController =
+ MediaCarouselController(
+ context,
+ mediaControlPanelFactory,
+ visualStabilityProvider,
+ mediaHostStatesManager,
+ activityStarter,
+ clock,
+ executor,
+ mediaDataManager,
+ configurationController,
+ falsingCollector,
+ falsingManager,
+ dumpManager,
+ logger,
+ debugLogger
+ )
verify(mediaDataManager).addListener(capture(listener))
verify(visualStabilityProvider)
.addPersistentReorderingAllowedListener(capture(visualStabilityCallback))
@@ -121,60 +122,139 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Test
fun testPlayerOrdering() {
// Test values: key, data, last active time
- val playingLocal = Triple("playing local",
- DATA.copy(active = true, isPlaying = true,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false),
- 4500L)
-
- val playingCast = Triple("playing cast",
- DATA.copy(active = true, isPlaying = true,
- playbackLocation = MediaData.PLAYBACK_CAST_LOCAL, resumption = false),
- 5000L)
-
- val pausedLocal = Triple("paused local",
- DATA.copy(active = true, isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false),
- 1000L)
-
- val pausedCast = Triple("paused cast",
- DATA.copy(active = true, isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_CAST_LOCAL, resumption = false),
- 2000L)
-
- val playingRcn = Triple("playing RCN",
- DATA.copy(active = true, isPlaying = true,
- playbackLocation = MediaData.PLAYBACK_CAST_REMOTE, resumption = false),
- 5000L)
-
- val pausedRcn = Triple("paused RCN",
- DATA.copy(active = true, isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_CAST_REMOTE, resumption = false),
- 5000L)
-
- val active = Triple("active",
- DATA.copy(active = true, isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true),
- 250L)
-
- val resume1 = Triple("resume 1",
- DATA.copy(active = false, isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true),
- 500L)
-
- val resume2 = Triple("resume 2",
- DATA.copy(active = false, isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true),
- 1000L)
-
- val activeMoreRecent = Triple("active more recent",
- DATA.copy(active = false, isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true, lastActive = 2L),
- 1000L)
-
- val activeLessRecent = Triple("active less recent",
- DATA.copy(active = false, isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true, lastActive = 1L),
- 1000L)
+ val playingLocal =
+ Triple(
+ "playing local",
+ DATA.copy(
+ active = true,
+ isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = false
+ ),
+ 4500L
+ )
+
+ val playingCast =
+ Triple(
+ "playing cast",
+ DATA.copy(
+ active = true,
+ isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_CAST_LOCAL,
+ resumption = false
+ ),
+ 5000L
+ )
+
+ val pausedLocal =
+ Triple(
+ "paused local",
+ DATA.copy(
+ active = true,
+ isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = false
+ ),
+ 1000L
+ )
+
+ val pausedCast =
+ Triple(
+ "paused cast",
+ DATA.copy(
+ active = true,
+ isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_CAST_LOCAL,
+ resumption = false
+ ),
+ 2000L
+ )
+
+ val playingRcn =
+ Triple(
+ "playing RCN",
+ DATA.copy(
+ active = true,
+ isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_CAST_REMOTE,
+ resumption = false
+ ),
+ 5000L
+ )
+
+ val pausedRcn =
+ Triple(
+ "paused RCN",
+ DATA.copy(
+ active = true,
+ isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_CAST_REMOTE,
+ resumption = false
+ ),
+ 5000L
+ )
+
+ val active =
+ Triple(
+ "active",
+ DATA.copy(
+ active = true,
+ isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = true
+ ),
+ 250L
+ )
+
+ val resume1 =
+ Triple(
+ "resume 1",
+ DATA.copy(
+ active = false,
+ isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = true
+ ),
+ 500L
+ )
+
+ val resume2 =
+ Triple(
+ "resume 2",
+ DATA.copy(
+ active = false,
+ isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = true
+ ),
+ 1000L
+ )
+
+ val activeMoreRecent =
+ Triple(
+ "active more recent",
+ DATA.copy(
+ active = false,
+ isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = true,
+ lastActive = 2L
+ ),
+ 1000L
+ )
+
+ val activeLessRecent =
+ Triple(
+ "active less recent",
+ DATA.copy(
+ active = false,
+ isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = true,
+ lastActive = 1L
+ ),
+ 1000L
+ )
// Expected ordering for media players:
// Actively playing local sessions
// Actively playing cast sessions
@@ -182,13 +262,28 @@ class MediaCarouselControllerTest : SysuiTestCase() {
// RCNs
// Resume controls, by last active
- val expected = listOf(playingLocal, playingCast, pausedCast, pausedLocal, playingRcn,
- pausedRcn, active, resume2, resume1)
+ val expected =
+ listOf(
+ playingLocal,
+ playingCast,
+ pausedCast,
+ pausedLocal,
+ playingRcn,
+ pausedRcn,
+ active,
+ resume2,
+ resume1
+ )
expected.forEach {
clock.setCurrentTimeMillis(it.third)
- MediaPlayerData.addMediaPlayer(it.first, it.second.copy(notificationKey = it.first),
- panel, clock, isSsReactivated = false)
+ MediaPlayerData.addMediaPlayer(
+ it.first,
+ it.second.copy(notificationKey = it.first),
+ panel,
+ clock,
+ isSsReactivated = false
+ )
}
for ((index, key) in MediaPlayerData.playerKeys().withIndex()) {
@@ -205,8 +300,13 @@ class MediaCarouselControllerTest : SysuiTestCase() {
testPlayerOrdering()
// If smartspace is prioritized
- MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA, panel,
- true, clock)
+ MediaPlayerData.addMediaRecommendation(
+ SMARTSPACE_KEY,
+ EMPTY_SMARTSPACE_MEDIA_DATA,
+ panel,
+ true,
+ clock
+ )
// Then it should be shown immediately after any actively playing controls
assertTrue(MediaPlayerData.playerKeys().elementAt(2).isSsMediaRec)
@@ -218,9 +318,9 @@ class MediaCarouselControllerTest : SysuiTestCase() {
// If smartspace is prioritized
listener.value.onSmartspaceMediaDataLoaded(
- SMARTSPACE_KEY,
- EMPTY_SMARTSPACE_MEDIA_DATA.copy(isActive = true),
- true
+ SMARTSPACE_KEY,
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(isActive = true),
+ true
)
// Then it should be shown immediately after any actively playing controls
@@ -233,8 +333,13 @@ class MediaCarouselControllerTest : SysuiTestCase() {
testPlayerOrdering()
// If smartspace is not prioritized
- MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA, panel,
- false, clock)
+ MediaPlayerData.addMediaRecommendation(
+ SMARTSPACE_KEY,
+ EMPTY_SMARTSPACE_MEDIA_DATA,
+ panel,
+ false,
+ clock
+ )
// Then it should be shown at the end of the carousel's active entries
val idx = MediaPlayerData.playerKeys().count { it.data.active } - 1
@@ -245,25 +350,36 @@ class MediaCarouselControllerTest : SysuiTestCase() {
fun testPlayingExistingMediaPlayerFromCarousel_visibleMediaPlayersNotUpdated() {
testPlayerOrdering()
// playing paused player
- listener.value.onMediaDataLoaded("paused local",
- "paused local",
- DATA.copy(active = true, isPlaying = true,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false))
- listener.value.onMediaDataLoaded("playing local",
- "playing local",
- DATA.copy(active = true, isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true)
+ listener.value.onMediaDataLoaded(
+ "paused local",
+ "paused local",
+ DATA.copy(
+ active = true,
+ isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = false
+ )
+ )
+ listener.value.onMediaDataLoaded(
+ "playing local",
+ "playing local",
+ DATA.copy(
+ active = true,
+ isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = true
+ )
)
assertEquals(
- MediaPlayerData.getMediaPlayerIndex("paused local"),
- mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
+ MediaPlayerData.getMediaPlayerIndex("paused local"),
+ mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
)
// paused player order should stays the same in visibleMediaPLayer map.
// paused player order should be first in mediaPlayer map.
assertEquals(
- MediaPlayerData.visiblePlayerKeys().elementAt(3),
- MediaPlayerData.playerKeys().elementAt(0)
+ MediaPlayerData.visiblePlayerKeys().elementAt(3),
+ MediaPlayerData.playerKeys().elementAt(0)
)
}
@Test
@@ -285,7 +401,8 @@ class MediaCarouselControllerTest : SysuiTestCase() {
mediaCarouselController.onDesiredLocationChanged(
MediaHierarchyManager.LOCATION_QS,
mediaHostState,
- animate = false)
+ animate = false
+ )
verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_QS)
}
@@ -294,7 +411,8 @@ class MediaCarouselControllerTest : SysuiTestCase() {
mediaCarouselController.onDesiredLocationChanged(
MediaHierarchyManager.LOCATION_QQS,
mediaHostState,
- animate = false)
+ animate = false
+ )
verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_QQS)
}
@@ -303,7 +421,8 @@ class MediaCarouselControllerTest : SysuiTestCase() {
mediaCarouselController.onDesiredLocationChanged(
MediaHierarchyManager.LOCATION_LOCKSCREEN,
mediaHostState,
- animate = false)
+ animate = false
+ )
verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_LOCKSCREEN)
}
@@ -312,7 +431,8 @@ class MediaCarouselControllerTest : SysuiTestCase() {
mediaCarouselController.onDesiredLocationChanged(
MediaHierarchyManager.LOCATION_DREAM_OVERLAY,
mediaHostState,
- animate = false)
+ animate = false
+ )
verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_DREAM_OVERLAY)
}
@@ -321,10 +441,8 @@ class MediaCarouselControllerTest : SysuiTestCase() {
val packageName = "smartspace package"
val instanceId = InstanceId.fakeInstanceId(123)
- val smartspaceData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
- packageName = packageName,
- instanceId = instanceId
- )
+ val smartspaceData =
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(packageName = packageName, instanceId = instanceId)
MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, smartspaceData, panel, true, clock)
mediaCarouselController.removePlayer(SMARTSPACE_KEY)
@@ -333,64 +451,99 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Test
fun testMediaLoaded_ScrollToActivePlayer() {
- listener.value.onMediaDataLoaded("playing local",
- null,
- DATA.copy(active = true, isPlaying = true,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false)
+ listener.value.onMediaDataLoaded(
+ "playing local",
+ null,
+ DATA.copy(
+ active = true,
+ isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = false
+ )
+ )
+ listener.value.onMediaDataLoaded(
+ "paused local",
+ null,
+ DATA.copy(
+ active = true,
+ isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = false
+ )
)
- listener.value.onMediaDataLoaded("paused local",
- null,
- DATA.copy(active = true, isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false))
// adding a media recommendation card.
- listener.value.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, EMPTY_SMARTSPACE_MEDIA_DATA,
- false)
+ listener.value.onSmartspaceMediaDataLoaded(
+ SMARTSPACE_KEY,
+ EMPTY_SMARTSPACE_MEDIA_DATA,
+ false
+ )
mediaCarouselController.shouldScrollToKey = true
// switching between media players.
- listener.value.onMediaDataLoaded("playing local",
- "playing local",
- DATA.copy(active = true, isPlaying = false,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = true)
+ listener.value.onMediaDataLoaded(
+ "playing local",
+ "playing local",
+ DATA.copy(
+ active = true,
+ isPlaying = false,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = true
+ )
+ )
+ listener.value.onMediaDataLoaded(
+ "paused local",
+ "paused local",
+ DATA.copy(
+ active = true,
+ isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = false
+ )
)
- listener.value.onMediaDataLoaded("paused local",
- "paused local",
- DATA.copy(active = true, isPlaying = true,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false))
assertEquals(
- MediaPlayerData.getMediaPlayerIndex("paused local"),
- mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
+ MediaPlayerData.getMediaPlayerIndex("paused local"),
+ mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
)
}
@Test
fun testMediaLoadedFromRecommendationCard_ScrollToActivePlayer() {
listener.value.onSmartspaceMediaDataLoaded(
- SMARTSPACE_KEY,
- EMPTY_SMARTSPACE_MEDIA_DATA.copy(packageName = "PACKAGE_NAME", isActive = true),
- false
+ SMARTSPACE_KEY,
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(packageName = "PACKAGE_NAME", isActive = true),
+ false
)
- listener.value.onMediaDataLoaded("playing local",
- null,
- DATA.copy(active = true, isPlaying = true,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false)
+ listener.value.onMediaDataLoaded(
+ "playing local",
+ null,
+ DATA.copy(
+ active = true,
+ isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = false
+ )
)
var playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
assertEquals(
- playerIndex,
- mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
+ playerIndex,
+ mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex
)
assertEquals(playerIndex, 0)
// Replaying the same media player one more time.
// And check that the card stays in its position.
mediaCarouselController.shouldScrollToKey = true
- listener.value.onMediaDataLoaded("playing local",
- null,
- DATA.copy(active = true, isPlaying = true,
- playbackLocation = MediaData.PLAYBACK_LOCAL, resumption = false,
- packageName = "PACKAGE_NAME")
+ listener.value.onMediaDataLoaded(
+ "playing local",
+ null,
+ DATA.copy(
+ active = true,
+ isPlaying = true,
+ playbackLocation = MediaData.PLAYBACK_LOCAL,
+ resumption = false,
+ packageName = "PACKAGE_NAME"
+ )
)
playerIndex = MediaPlayerData.getMediaPlayerIndex("playing local")
assertEquals(playerIndex, 0)
@@ -423,37 +576,43 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Test
fun testGetCurrentVisibleMediaContentIntent() {
val clickIntent1 = mock(PendingIntent::class.java)
- val player1 = Triple("player1",
- DATA.copy(clickIntent = clickIntent1),
- 1000L)
+ val player1 = Triple("player1", DATA.copy(clickIntent = clickIntent1), 1000L)
clock.setCurrentTimeMillis(player1.third)
- MediaPlayerData.addMediaPlayer(player1.first,
- player1.second.copy(notificationKey = player1.first),
- panel, clock, isSsReactivated = false)
+ MediaPlayerData.addMediaPlayer(
+ player1.first,
+ player1.second.copy(notificationKey = player1.first),
+ panel,
+ clock,
+ isSsReactivated = false
+ )
assertEquals(mediaCarouselController.getCurrentVisibleMediaContentIntent(), clickIntent1)
val clickIntent2 = mock(PendingIntent::class.java)
- val player2 = Triple("player2",
- DATA.copy(clickIntent = clickIntent2),
- 2000L)
+ val player2 = Triple("player2", DATA.copy(clickIntent = clickIntent2), 2000L)
clock.setCurrentTimeMillis(player2.third)
- MediaPlayerData.addMediaPlayer(player2.first,
- player2.second.copy(notificationKey = player2.first),
- panel, clock, isSsReactivated = false)
+ MediaPlayerData.addMediaPlayer(
+ player2.first,
+ player2.second.copy(notificationKey = player2.first),
+ panel,
+ clock,
+ isSsReactivated = false
+ )
// mediaCarouselScrollHandler.visibleMediaIndex is unchanged (= 0), and the new player is
// added to the front because it was active more recently.
assertEquals(mediaCarouselController.getCurrentVisibleMediaContentIntent(), clickIntent2)
val clickIntent3 = mock(PendingIntent::class.java)
- val player3 = Triple("player3",
- DATA.copy(clickIntent = clickIntent3),
- 500L)
+ val player3 = Triple("player3", DATA.copy(clickIntent = clickIntent3), 500L)
clock.setCurrentTimeMillis(player3.third)
- MediaPlayerData.addMediaPlayer(player3.first,
- player3.second.copy(notificationKey = player3.first),
- panel, clock, isSsReactivated = false)
+ MediaPlayerData.addMediaPlayer(
+ player3.first,
+ player3.second.copy(notificationKey = player3.first),
+ panel,
+ clock,
+ isSsReactivated = false
+ )
// mediaCarouselScrollHandler.visibleMediaIndex is unchanged (= 0), and the new player is
// added to the end because it was active less recently.
@@ -463,10 +622,14 @@ class MediaCarouselControllerTest : SysuiTestCase() {
@Test
fun testSetCurrentState_UpdatePageIndicatorAlphaWhenSquish() {
val delta = 0.0001F
- val paginationSquishMiddle = TRANSFORM_BEZIER.getInterpolation(
- (PAGINATION_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION)
- val paginationSquishEnd = TRANSFORM_BEZIER.getInterpolation(
- (PAGINATION_DELAY + DURATION) / ANIMATION_BASE_DURATION)
+ val paginationSquishMiddle =
+ TRANSFORM_BEZIER.getInterpolation(
+ (PAGINATION_DELAY + DURATION / 2) / ANIMATION_BASE_DURATION
+ )
+ val paginationSquishEnd =
+ TRANSFORM_BEZIER.getInterpolation(
+ (PAGINATION_DELAY + DURATION) / ANIMATION_BASE_DURATION
+ )
whenever(mediaHostStatesManager.mediaHostStates)
.thenReturn(mutableMapOf(LOCATION_QS to mediaHostState))
whenever(mediaHostState.visible).thenReturn(true)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index faa76f423fae..584305334b6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -60,7 +60,6 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.bluetooth.BroadcastDialogController
import com.android.systemui.broadcast.BroadcastSender
import com.android.systemui.media.controls.MediaTestUtils
-import com.android.systemui.media.controls.pipeline.EMPTY_SMARTSPACE_MEDIA_DATA
import com.android.systemui.media.controls.models.GutsViewHolder
import com.android.systemui.media.controls.models.player.MediaAction
import com.android.systemui.media.controls.models.player.MediaButton
@@ -68,9 +67,10 @@ import com.android.systemui.media.controls.models.player.MediaData
import com.android.systemui.media.controls.models.player.MediaDeviceData
import com.android.systemui.media.controls.models.player.MediaViewHolder
import com.android.systemui.media.controls.models.player.SeekBarViewModel
+import com.android.systemui.media.controls.models.recommendation.KEY_SMARTSPACE_APP_NAME
import com.android.systemui.media.controls.models.recommendation.RecommendationViewHolder
import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData
-import com.android.systemui.media.controls.models.recommendation.KEY_SMARTSPACE_APP_NAME
+import com.android.systemui.media.controls.pipeline.EMPTY_SMARTSPACE_MEDIA_DATA
import com.android.systemui.media.controls.pipeline.MediaDataManager
import com.android.systemui.media.controls.util.MediaUiEventLogger
import com.android.systemui.media.dialog.MediaOutputDialogFactory
@@ -177,8 +177,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var session: MediaSession
private lateinit var device: MediaDeviceData
- private val disabledDevice = MediaDeviceData(false, null, DISABLED_DEVICE_NAME, null,
- showBroadcastButton = false)
+ private val disabledDevice =
+ MediaDeviceData(false, null, DISABLED_DEVICE_NAME, null, showBroadcastButton = false)
private lateinit var mediaData: MediaData
private val clock = FakeSystemClock()
@Mock private lateinit var logger: MediaUiEventLogger
@@ -225,24 +225,27 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(packageManager.getApplicationLabel(any())).thenReturn(PACKAGE)
context.setMockPackageManager(packageManager)
- player = object : MediaControlPanel(
- context,
- bgExecutor,
- mainExecutor,
- activityStarter,
- broadcastSender,
- mediaViewController,
- seekBarViewModel,
- Lazy { mediaDataManager },
- mediaOutputDialogFactory,
- mediaCarouselController,
- falsingManager,
- clock,
- logger,
- keyguardStateController,
- activityIntentHelper,
- lockscreenUserManager,
- broadcastDialogController) {
+ player =
+ object :
+ MediaControlPanel(
+ context,
+ bgExecutor,
+ mainExecutor,
+ activityStarter,
+ broadcastSender,
+ mediaViewController,
+ seekBarViewModel,
+ Lazy { mediaDataManager },
+ mediaOutputDialogFactory,
+ mediaCarouselController,
+ falsingManager,
+ clock,
+ logger,
+ keyguardStateController,
+ activityIntentHelper,
+ lockscreenUserManager,
+ broadcastDialogController
+ ) {
override fun loadAnimator(
animId: Int,
otionInterpolator: Interpolator,
@@ -263,18 +266,20 @@ public class MediaControlPanelTest : SysuiTestCase() {
// Set valid recommendation data
val extras = Bundle()
extras.putString(KEY_SMARTSPACE_APP_NAME, REC_APP_NAME)
- val intent = Intent().apply {
- putExtras(extras)
- setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- }
+ val intent =
+ Intent().apply {
+ putExtras(extras)
+ setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+ }
whenever(smartspaceAction.intent).thenReturn(intent)
whenever(smartspaceAction.extras).thenReturn(extras)
- smartspaceData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
- packageName = PACKAGE,
- instanceId = instanceId,
- recommendations = listOf(smartspaceAction, smartspaceAction, smartspaceAction),
- cardAction = smartspaceAction
- )
+ smartspaceData =
+ EMPTY_SMARTSPACE_MEDIA_DATA.copy(
+ packageName = PACKAGE,
+ instanceId = instanceId,
+ recommendations = listOf(smartspaceAction, smartspaceAction, smartspaceAction),
+ cardAction = smartspaceAction
+ )
}
private fun initGutsViewHolderMocks() {
@@ -292,36 +297,39 @@ public class MediaControlPanelTest : SysuiTestCase() {
}
private fun initDeviceMediaData(shouldShowBroadcastButton: Boolean, name: String) {
- device = MediaDeviceData(true, null, name, null,
- showBroadcastButton = shouldShowBroadcastButton)
+ device =
+ MediaDeviceData(true, null, name, null, showBroadcastButton = shouldShowBroadcastButton)
// Create media session
- val metadataBuilder = MediaMetadata.Builder().apply {
- putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
- putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
- }
- val playbackBuilder = PlaybackState.Builder().apply {
- setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
- setActions(PlaybackState.ACTION_PLAY)
- }
- session = MediaSession(context, SESSION_KEY).apply {
- setMetadata(metadataBuilder.build())
- setPlaybackState(playbackBuilder.build())
- }
+ val metadataBuilder =
+ MediaMetadata.Builder().apply {
+ putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
+ putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
+ }
+ val playbackBuilder =
+ PlaybackState.Builder().apply {
+ setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
+ setActions(PlaybackState.ACTION_PLAY)
+ }
+ session =
+ MediaSession(context, SESSION_KEY).apply {
+ setMetadata(metadataBuilder.build())
+ setPlaybackState(playbackBuilder.build())
+ }
session.setActive(true)
- mediaData = MediaTestUtils.emptyMediaData.copy(
+ mediaData =
+ MediaTestUtils.emptyMediaData.copy(
artist = ARTIST,
song = TITLE,
packageName = PACKAGE,
token = session.sessionToken,
device = device,
- instanceId = instanceId)
+ instanceId = instanceId
+ )
}
- /**
- * Initialize elements in media view holder
- */
+ /** Initialize elements in media view holder */
private fun initMediaViewHolderMocks() {
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
@@ -362,7 +370,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
action1.id,
action2.id,
action3.id,
- action4.id)
+ action4.id
+ )
}
whenever(viewHolder.player).thenReturn(view)
@@ -407,9 +416,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(viewHolder.actionsTopBarrier).thenReturn(actionsTopBarrier)
}
- /**
- * Initialize elements for the recommendation view holder
- */
+ /** Initialize elements for the recommendation view holder */
private fun initRecommendationViewHolderMocks() {
recTitle1 = TextView(context)
recTitle2 = TextView(context)
@@ -432,9 +439,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
.thenReturn(listOf(coverContainer1, coverContainer2, coverContainer3))
whenever(recommendationViewHolder.mediaTitles)
.thenReturn(listOf(recTitle1, recTitle2, recTitle3))
- whenever(recommendationViewHolder.mediaSubtitles).thenReturn(
- listOf(recSubtitle1, recSubtitle2, recSubtitle3)
- )
+ whenever(recommendationViewHolder.mediaSubtitles)
+ .thenReturn(listOf(recSubtitle1, recSubtitle2, recSubtitle3))
whenever(recommendationViewHolder.gutsViewHolder).thenReturn(gutsViewHolder)
@@ -466,12 +472,13 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindSemanticActions() {
val icon = context.getDrawable(android.R.drawable.ic_media_play)
val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
- val semanticActions = MediaButton(
- playOrPause = MediaAction(icon, Runnable {}, "play", bg),
- nextOrCustom = MediaAction(icon, Runnable {}, "next", bg),
- custom0 = MediaAction(icon, null, "custom 0", bg),
- custom1 = MediaAction(icon, null, "custom 1", bg)
- )
+ val semanticActions =
+ MediaButton(
+ playOrPause = MediaAction(icon, Runnable {}, "play", bg),
+ nextOrCustom = MediaAction(icon, Runnable {}, "next", bg),
+ custom0 = MediaAction(icon, null, "custom 0", bg),
+ custom1 = MediaAction(icon, null, "custom 1", bg)
+ )
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
player.bindPlayer(state, PACKAGE)
@@ -514,15 +521,16 @@ public class MediaControlPanelTest : SysuiTestCase() {
val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
// Setup button state: no prev or next button and their slots reserved
- val semanticActions = MediaButton(
- playOrPause = MediaAction(icon, Runnable {}, "play", bg),
- nextOrCustom = null,
- prevOrCustom = null,
- custom0 = MediaAction(icon, null, "custom 0", bg),
- custom1 = MediaAction(icon, null, "custom 1", bg),
- false,
- true
- )
+ val semanticActions =
+ MediaButton(
+ playOrPause = MediaAction(icon, Runnable {}, "play", bg),
+ nextOrCustom = null,
+ prevOrCustom = null,
+ custom0 = MediaAction(icon, null, "custom 0", bg),
+ custom1 = MediaAction(icon, null, "custom 1", bg),
+ false,
+ true
+ )
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
@@ -543,15 +551,16 @@ public class MediaControlPanelTest : SysuiTestCase() {
val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
// Setup button state: no prev or next button and their slots reserved
- val semanticActions = MediaButton(
- playOrPause = MediaAction(icon, Runnable {}, "play", bg),
- nextOrCustom = null,
- prevOrCustom = null,
- custom0 = MediaAction(icon, null, "custom 0", bg),
- custom1 = MediaAction(icon, null, "custom 1", bg),
- true,
- false
- )
+ val semanticActions =
+ MediaButton(
+ playOrPause = MediaAction(icon, Runnable {}, "play", bg),
+ nextOrCustom = null,
+ prevOrCustom = null,
+ custom0 = MediaAction(icon, null, "custom 0", bg),
+ custom1 = MediaAction(icon, null, "custom 1", bg),
+ true,
+ false
+ )
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
@@ -659,10 +668,11 @@ public class MediaControlPanelTest : SysuiTestCase() {
useRealConstraintSets()
val icon = context.getDrawable(android.R.drawable.ic_media_play)
- val semanticActions = MediaButton(
- playOrPause = MediaAction(icon, Runnable {}, "play", null),
- nextOrCustom = MediaAction(icon, Runnable {}, "next", null)
- )
+ val semanticActions =
+ MediaButton(
+ playOrPause = MediaAction(icon, Runnable {}, "play", null),
+ nextOrCustom = MediaAction(icon, Runnable {}, "next", null)
+ )
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
@@ -732,9 +742,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
useRealConstraintSets()
val icon = context.getDrawable(android.R.drawable.ic_media_play)
- val semanticActions = MediaButton(
- nextOrCustom = MediaAction(icon, Runnable {}, "next", null)
- )
+ val semanticActions =
+ MediaButton(nextOrCustom = MediaAction(icon, Runnable {}, "next", null))
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
@@ -749,10 +758,11 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun bind_notScrubbing_scrubbingViewsGone() {
val icon = context.getDrawable(android.R.drawable.ic_media_play)
- val semanticActions = MediaButton(
- prevOrCustom = MediaAction(icon, {}, "prev", null),
- nextOrCustom = MediaAction(icon, {}, "next", null)
- )
+ val semanticActions =
+ MediaButton(
+ prevOrCustom = MediaAction(icon, {}, "prev", null),
+ nextOrCustom = MediaAction(icon, {}, "next", null)
+ )
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
@@ -783,10 +793,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun setIsScrubbing_noPrevButton_scrubbingTimesNotShown() {
val icon = context.getDrawable(android.R.drawable.ic_media_play)
- val semanticActions = MediaButton(
- prevOrCustom = null,
- nextOrCustom = MediaAction(icon, {}, "next", null)
- )
+ val semanticActions =
+ MediaButton(prevOrCustom = null, nextOrCustom = MediaAction(icon, {}, "next", null))
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
player.bindPlayer(state, PACKAGE)
@@ -803,10 +811,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun setIsScrubbing_noNextButton_scrubbingTimesNotShown() {
val icon = context.getDrawable(android.R.drawable.ic_media_play)
- val semanticActions = MediaButton(
- prevOrCustom = MediaAction(icon, {}, "prev", null),
- nextOrCustom = null
- )
+ val semanticActions =
+ MediaButton(prevOrCustom = MediaAction(icon, {}, "prev", null), nextOrCustom = null)
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
player.bindPlayer(state, PACKAGE)
@@ -823,10 +829,11 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun setIsScrubbing_true_scrubbingViewsShownAndPrevNextHiddenOnlyInExpanded() {
val icon = context.getDrawable(android.R.drawable.ic_media_play)
- val semanticActions = MediaButton(
- prevOrCustom = MediaAction(icon, {}, "prev", null),
- nextOrCustom = MediaAction(icon, {}, "next", null)
- )
+ val semanticActions =
+ MediaButton(
+ prevOrCustom = MediaAction(icon, {}, "prev", null),
+ nextOrCustom = MediaAction(icon, {}, "next", null)
+ )
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
player.bindPlayer(state, PACKAGE)
@@ -845,10 +852,11 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun setIsScrubbing_trueThenFalse_scrubbingTimeGoneAtEnd() {
val icon = context.getDrawable(android.R.drawable.ic_media_play)
- val semanticActions = MediaButton(
- prevOrCustom = MediaAction(icon, {}, "prev", null),
- nextOrCustom = MediaAction(icon, {}, "next", null)
- )
+ val semanticActions =
+ MediaButton(
+ prevOrCustom = MediaAction(icon, {}, "prev", null),
+ nextOrCustom = MediaAction(icon, {}, "next", null)
+ )
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
@@ -872,18 +880,20 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindNotificationActions() {
val icon = context.getDrawable(android.R.drawable.ic_media_play)
val bg = context.getDrawable(R.drawable.qs_media_round_button_background)
- val actions = listOf(
- MediaAction(icon, Runnable {}, "previous", bg),
- MediaAction(icon, Runnable {}, "play", bg),
- MediaAction(icon, null, "next", bg),
- MediaAction(icon, null, "custom 0", bg),
- MediaAction(icon, Runnable {}, "custom 1", bg)
- )
- val state = mediaData.copy(
- actions = actions,
- actionsToShowInCompact = listOf(1, 2),
- semanticActions = null
- )
+ val actions =
+ listOf(
+ MediaAction(icon, Runnable {}, "previous", bg),
+ MediaAction(icon, Runnable {}, "play", bg),
+ MediaAction(icon, null, "next", bg),
+ MediaAction(icon, null, "custom 0", bg),
+ MediaAction(icon, Runnable {}, "custom 1", bg)
+ )
+ val state =
+ mediaData.copy(
+ actions = actions,
+ actionsToShowInCompact = listOf(1, 2),
+ semanticActions = null
+ )
player.attachPlayer(viewHolder)
player.bindPlayer(state, PACKAGE)
@@ -931,15 +941,12 @@ public class MediaControlPanelTest : SysuiTestCase() {
val icon = context.getDrawable(R.drawable.ic_media_play)
val bg = context.getDrawable(R.drawable.ic_media_play_container)
- val semanticActions0 = MediaButton(
- playOrPause = MediaAction(mockAvd0, Runnable {}, "play", null)
- )
- val semanticActions1 = MediaButton(
- playOrPause = MediaAction(mockAvd1, Runnable {}, "pause", null)
- )
- val semanticActions2 = MediaButton(
- playOrPause = MediaAction(mockAvd2, Runnable {}, "loading", null)
- )
+ val semanticActions0 =
+ MediaButton(playOrPause = MediaAction(mockAvd0, Runnable {}, "play", null))
+ val semanticActions1 =
+ MediaButton(playOrPause = MediaAction(mockAvd1, Runnable {}, "pause", null))
+ val semanticActions2 =
+ MediaButton(playOrPause = MediaAction(mockAvd2, Runnable {}, "loading", null))
val state0 = mediaData.copy(semanticActions = semanticActions0)
val state1 = mediaData.copy(semanticActions = semanticActions1)
val state2 = mediaData.copy(semanticActions = semanticActions2)
@@ -1102,11 +1109,10 @@ public class MediaControlPanelTest : SysuiTestCase() {
val mockAvd0 = mock(AnimatedVectorDrawable::class.java)
whenever(mockAvd0.mutate()).thenReturn(mockAvd0)
- val semanticActions0 = MediaButton(
- playOrPause = MediaAction(mockAvd0, Runnable {}, "play", null)
- )
- val state = mediaData.copy(resumption = true, semanticActions = semanticActions0,
- isPlaying = false)
+ val semanticActions0 =
+ MediaButton(playOrPause = MediaAction(mockAvd0, Runnable {}, "play", null))
+ val state =
+ mediaData.copy(resumption = true, semanticActions = semanticActions0, isPlaying = false)
player.attachPlayer(viewHolder)
player.bindPlayer(state, PACKAGE)
assertThat(seamlessText.getText()).isEqualTo(APP_NAME)
@@ -1445,9 +1451,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun actionPlayPauseClick_isLogged() {
- val semanticActions = MediaButton(
- playOrPause = MediaAction(null, Runnable {}, "play", null)
- )
+ val semanticActions =
+ MediaButton(playOrPause = MediaAction(null, Runnable {}, "play", null))
val data = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
@@ -1459,9 +1464,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun actionPrevClick_isLogged() {
- val semanticActions = MediaButton(
- prevOrCustom = MediaAction(null, Runnable {}, "previous", null)
- )
+ val semanticActions =
+ MediaButton(prevOrCustom = MediaAction(null, Runnable {}, "previous", null))
val data = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
@@ -1473,9 +1477,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun actionNextClick_isLogged() {
- val semanticActions = MediaButton(
- nextOrCustom = MediaAction(null, Runnable {}, "next", null)
- )
+ val semanticActions =
+ MediaButton(nextOrCustom = MediaAction(null, Runnable {}, "next", null))
val data = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
@@ -1487,9 +1490,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun actionCustom0Click_isLogged() {
- val semanticActions = MediaButton(
- custom0 = MediaAction(null, Runnable {}, "custom 0", null)
- )
+ val semanticActions =
+ MediaButton(custom0 = MediaAction(null, Runnable {}, "custom 0", null))
val data = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
@@ -1501,9 +1503,8 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun actionCustom1Click_isLogged() {
- val semanticActions = MediaButton(
- custom1 = MediaAction(null, Runnable {}, "custom 1", null)
- )
+ val semanticActions =
+ MediaButton(custom1 = MediaAction(null, Runnable {}, "custom 1", null))
val data = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
@@ -1515,13 +1516,14 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun actionCustom2Click_isLogged() {
- val actions = listOf(
- MediaAction(null, Runnable {}, "action 0", null),
- MediaAction(null, Runnable {}, "action 1", null),
- MediaAction(null, Runnable {}, "action 2", null),
- MediaAction(null, Runnable {}, "action 3", null),
- MediaAction(null, Runnable {}, "action 4", null)
- )
+ val actions =
+ listOf(
+ MediaAction(null, Runnable {}, "action 0", null),
+ MediaAction(null, Runnable {}, "action 1", null),
+ MediaAction(null, Runnable {}, "action 2", null),
+ MediaAction(null, Runnable {}, "action 3", null),
+ MediaAction(null, Runnable {}, "action 4", null)
+ )
val data = mediaData.copy(actions = actions)
player.attachPlayer(viewHolder)
@@ -1533,13 +1535,14 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun actionCustom3Click_isLogged() {
- val actions = listOf(
- MediaAction(null, Runnable {}, "action 0", null),
- MediaAction(null, Runnable {}, "action 1", null),
- MediaAction(null, Runnable {}, "action 2", null),
- MediaAction(null, Runnable {}, "action 3", null),
- MediaAction(null, Runnable {}, "action 4", null)
- )
+ val actions =
+ listOf(
+ MediaAction(null, Runnable {}, "action 0", null),
+ MediaAction(null, Runnable {}, "action 1", null),
+ MediaAction(null, Runnable {}, "action 2", null),
+ MediaAction(null, Runnable {}, "action 3", null),
+ MediaAction(null, Runnable {}, "action 4", null)
+ )
val data = mediaData.copy(actions = actions)
player.attachPlayer(viewHolder)
@@ -1551,13 +1554,14 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun actionCustom4Click_isLogged() {
- val actions = listOf(
- MediaAction(null, Runnable {}, "action 0", null),
- MediaAction(null, Runnable {}, "action 1", null),
- MediaAction(null, Runnable {}, "action 2", null),
- MediaAction(null, Runnable {}, "action 3", null),
- MediaAction(null, Runnable {}, "action 4", null)
- )
+ val actions =
+ listOf(
+ MediaAction(null, Runnable {}, "action 0", null),
+ MediaAction(null, Runnable {}, "action 1", null),
+ MediaAction(null, Runnable {}, "action 2", null),
+ MediaAction(null, Runnable {}, "action 3", null),
+ MediaAction(null, Runnable {}, "action 4", null)
+ )
val data = mediaData.copy(actions = actions)
player.attachPlayer(viewHolder)
@@ -1621,8 +1625,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
// THEN it shows without dismissing keyguard first
captor.value.onClick(viewHolder.player)
- verify(activityStarter).startActivity(eq(clickIntent), eq(true),
- nullable(), eq(true))
+ verify(activityStarter).startActivity(eq(clickIntent), eq(true), nullable(), eq(true))
}
@Test
@@ -1710,20 +1713,22 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindRecommendation_listHasTooFewRecs_notDisplayed() {
player.attachRecommendation(recommendationViewHolder)
val icon = Icon.createWithResource(context, R.drawable.ic_1x_mobiledata)
- val data = smartspaceData.copy(
- recommendations = listOf(
- SmartspaceAction.Builder("id1", "title1")
- .setSubtitle("subtitle1")
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id2", "title2")
- .setSubtitle("subtitle2")
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build(),
+ val data =
+ smartspaceData.copy(
+ recommendations =
+ listOf(
+ SmartspaceAction.Builder("id1", "title1")
+ .setSubtitle("subtitle1")
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id2", "title2")
+ .setSubtitle("subtitle2")
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ )
)
- )
player.bindRecommendation(data)
@@ -1735,30 +1740,32 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindRecommendation_listHasTooFewRecsWithIcons_notDisplayed() {
player.attachRecommendation(recommendationViewHolder)
val icon = Icon.createWithResource(context, R.drawable.ic_1x_mobiledata)
- val data = smartspaceData.copy(
- recommendations = listOf(
- SmartspaceAction.Builder("id1", "title1")
- .setSubtitle("subtitle1")
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id2", "title2")
- .setSubtitle("subtitle2")
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id2", "empty icon 1")
- .setSubtitle("subtitle2")
- .setIcon(null)
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id2", "empty icon 2")
- .setSubtitle("subtitle2")
- .setIcon(null)
- .setExtras(Bundle.EMPTY)
- .build(),
+ val data =
+ smartspaceData.copy(
+ recommendations =
+ listOf(
+ SmartspaceAction.Builder("id1", "title1")
+ .setSubtitle("subtitle1")
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id2", "title2")
+ .setSubtitle("subtitle2")
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id2", "empty icon 1")
+ .setSubtitle("subtitle2")
+ .setIcon(null)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id2", "empty icon 2")
+ .setSubtitle("subtitle2")
+ .setIcon(null)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ )
)
- )
player.bindRecommendation(data)
@@ -1778,25 +1785,27 @@ public class MediaControlPanelTest : SysuiTestCase() {
val subtitle3 = "Subtitle3"
val icon = Icon.createWithResource(context, R.drawable.ic_1x_mobiledata)
- val data = smartspaceData.copy(
- recommendations = listOf(
- SmartspaceAction.Builder("id1", title1)
- .setSubtitle(subtitle1)
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id2", title2)
- .setSubtitle(subtitle2)
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id3", title3)
- .setSubtitle(subtitle3)
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build()
+ val data =
+ smartspaceData.copy(
+ recommendations =
+ listOf(
+ SmartspaceAction.Builder("id1", title1)
+ .setSubtitle(subtitle1)
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id2", title2)
+ .setSubtitle(subtitle2)
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id3", title3)
+ .setSubtitle(subtitle3)
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build()
+ )
)
- )
player.bindRecommendation(data)
assertThat(recTitle1.text).isEqualTo(title1)
@@ -1811,15 +1820,17 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindRecommendation_noTitle_subtitleNotShown() {
player.attachRecommendation(recommendationViewHolder)
- val data = smartspaceData.copy(
- recommendations = listOf(
- SmartspaceAction.Builder("id1", "")
- .setSubtitle("fake subtitle")
- .setIcon(Icon.createWithResource(context, R.drawable.ic_1x_mobiledata))
- .setExtras(Bundle.EMPTY)
- .build()
+ val data =
+ smartspaceData.copy(
+ recommendations =
+ listOf(
+ SmartspaceAction.Builder("id1", "")
+ .setSubtitle("fake subtitle")
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_1x_mobiledata))
+ .setExtras(Bundle.EMPTY)
+ .build()
+ )
)
- )
player.bindRecommendation(data)
assertThat(recSubtitle1.text).isEqualTo("")
@@ -1831,25 +1842,27 @@ public class MediaControlPanelTest : SysuiTestCase() {
player.attachRecommendation(recommendationViewHolder)
val icon = Icon.createWithResource(context, R.drawable.ic_1x_mobiledata)
- val data = smartspaceData.copy(
- recommendations = listOf(
- SmartspaceAction.Builder("id1", "")
- .setSubtitle("fake subtitle")
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id2", "title2")
- .setSubtitle("fake subtitle")
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id3", "")
- .setSubtitle("fake subtitle")
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build()
+ val data =
+ smartspaceData.copy(
+ recommendations =
+ listOf(
+ SmartspaceAction.Builder("id1", "")
+ .setSubtitle("fake subtitle")
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id2", "title2")
+ .setSubtitle("fake subtitle")
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id3", "")
+ .setSubtitle("fake subtitle")
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build()
+ )
)
- )
player.bindRecommendation(data)
assertThat(expandedSet.getVisibility(recTitle1.id)).isEqualTo(ConstraintSet.VISIBLE)
@@ -1863,25 +1876,27 @@ public class MediaControlPanelTest : SysuiTestCase() {
player.attachRecommendation(recommendationViewHolder)
val icon = Icon.createWithResource(context, R.drawable.ic_1x_mobiledata)
- val data = smartspaceData.copy(
- recommendations = listOf(
- SmartspaceAction.Builder("id1", "")
- .setSubtitle("")
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id2", "title2")
- .setSubtitle("")
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id3", "title3")
- .setSubtitle("subtitle3")
- .setIcon(icon)
- .setExtras(Bundle.EMPTY)
- .build()
+ val data =
+ smartspaceData.copy(
+ recommendations =
+ listOf(
+ SmartspaceAction.Builder("id1", "")
+ .setSubtitle("")
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id2", "title2")
+ .setSubtitle("")
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id3", "title3")
+ .setSubtitle("subtitle3")
+ .setIcon(icon)
+ .setExtras(Bundle.EMPTY)
+ .build()
+ )
)
- )
player.bindRecommendation(data)
assertThat(expandedSet.getVisibility(recSubtitle1.id)).isEqualTo(ConstraintSet.VISIBLE)
@@ -1893,25 +1908,27 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindRecommendation_noneHaveSubtitles_subtitleViewsGone() {
useRealConstraintSets()
player.attachRecommendation(recommendationViewHolder)
- val data = smartspaceData.copy(
- recommendations = listOf(
- SmartspaceAction.Builder("id1", "title1")
- .setSubtitle("")
- .setIcon(Icon.createWithResource(context, R.drawable.ic_1x_mobiledata))
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id2", "title2")
- .setSubtitle("")
- .setIcon(Icon.createWithResource(context, R.drawable.ic_alarm))
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id3", "title3")
- .setSubtitle("")
- .setIcon(Icon.createWithResource(context, R.drawable.ic_3g_mobiledata))
- .setExtras(Bundle.EMPTY)
- .build()
+ val data =
+ smartspaceData.copy(
+ recommendations =
+ listOf(
+ SmartspaceAction.Builder("id1", "title1")
+ .setSubtitle("")
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_1x_mobiledata))
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id2", "title2")
+ .setSubtitle("")
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_alarm))
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id3", "title3")
+ .setSubtitle("")
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_3g_mobiledata))
+ .setExtras(Bundle.EMPTY)
+ .build()
+ )
)
- )
player.bindRecommendation(data)
@@ -1924,25 +1941,27 @@ public class MediaControlPanelTest : SysuiTestCase() {
fun bindRecommendation_noneHaveTitles_titleAndSubtitleViewsGone() {
useRealConstraintSets()
player.attachRecommendation(recommendationViewHolder)
- val data = smartspaceData.copy(
- recommendations = listOf(
- SmartspaceAction.Builder("id1", "")
- .setSubtitle("subtitle1")
- .setIcon(Icon.createWithResource(context, R.drawable.ic_1x_mobiledata))
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id2", "")
- .setSubtitle("subtitle2")
- .setIcon(Icon.createWithResource(context, R.drawable.ic_alarm))
- .setExtras(Bundle.EMPTY)
- .build(),
- SmartspaceAction.Builder("id3", "")
- .setSubtitle("subtitle3")
- .setIcon(Icon.createWithResource(context, R.drawable.ic_3g_mobiledata))
- .setExtras(Bundle.EMPTY)
- .build()
+ val data =
+ smartspaceData.copy(
+ recommendations =
+ listOf(
+ SmartspaceAction.Builder("id1", "")
+ .setSubtitle("subtitle1")
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_1x_mobiledata))
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id2", "")
+ .setSubtitle("subtitle2")
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_alarm))
+ .setExtras(Bundle.EMPTY)
+ .build(),
+ SmartspaceAction.Builder("id3", "")
+ .setSubtitle("subtitle3")
+ .setIcon(Icon.createWithResource(context, R.drawable.ic_3g_mobiledata))
+ .setExtras(Bundle.EMPTY)
+ .build()
+ )
)
- )
player.bindRecommendation(data)
@@ -1955,20 +1974,23 @@ public class MediaControlPanelTest : SysuiTestCase() {
}
private fun getScrubbingChangeListener(): SeekBarViewModel.ScrubbingChangeListener =
- withArgCaptor { verify(seekBarViewModel).setScrubbingChangeListener(capture()) }
+ withArgCaptor {
+ verify(seekBarViewModel).setScrubbingChangeListener(capture())
+ }
- private fun getEnabledChangeListener(): SeekBarViewModel.EnabledChangeListener =
- withArgCaptor { verify(seekBarViewModel).setEnabledChangeListener(capture()) }
+ private fun getEnabledChangeListener(): SeekBarViewModel.EnabledChangeListener = withArgCaptor {
+ verify(seekBarViewModel).setEnabledChangeListener(capture())
+ }
/**
- * Update our test to use real ConstraintSets instead of mocks.
+ * Update our test to use real ConstraintSets instead of mocks.
*
- * Some item visibilities, such as the seekbar visibility, are dependent on other action's
- * visibilities. If we use mocks for the ConstraintSets, then action visibility changes are
- * just thrown away instead of being saved for reference later. This method sets us up to use
- * ConstraintSets so that we do save visibility changes.
+ * Some item visibilities, such as the seekbar visibility, are dependent on other action's
+ * visibilities. If we use mocks for the ConstraintSets, then action visibility changes are just
+ * thrown away instead of being saved for reference later. This method sets us up to use
+ * ConstraintSets so that we do save visibility changes.
*
- * TODO(b/229740380): Can/should we use real expanded and collapsed sets for all tests?
+ * TODO(b/229740380): Can/should we use real expanded and collapsed sets for all tests?
*/
private fun useRealConstraintSets() {
expandedSet = ConstraintSet()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
index 2a46f037431f..071604dc5790 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaHierarchyManagerTest.kt
@@ -84,10 +84,8 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
private lateinit var statusBarCallback: ArgumentCaptor<(StatusBarStateController.StateListener)>
@Captor
private lateinit var dreamOverlayCallback:
- ArgumentCaptor<(DreamOverlayStateController.Callback)>
- @JvmField
- @Rule
- val mockito = MockitoJUnit.rule()
+ ArgumentCaptor<(DreamOverlayStateController.Callback)>
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
private lateinit var mediaHierarchyManager: MediaHierarchyManager
private lateinit var mediaFrame: ViewGroup
private val configurationController = FakeConfigurationController()
@@ -98,13 +96,15 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
@Before
fun setup() {
- context.getOrCreateTestableResources().addOverride(
- R.bool.config_use_split_notification_shade, false)
+ context
+ .getOrCreateTestableResources()
+ .addOverride(R.bool.config_use_split_notification_shade, false)
mediaFrame = FrameLayout(context)
testableLooper = TestableLooper.get(this)
fakeHandler = FakeHandler(testableLooper.looper)
whenever(mediaCarouselController.mediaFrame).thenReturn(mediaFrame)
- mediaHierarchyManager = MediaHierarchyManager(
+ mediaHierarchyManager =
+ MediaHierarchyManager(
context,
statusBarStateController,
keyguardStateController,
@@ -116,7 +116,8 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
wakefulnessLifecycle,
notifPanelEvents,
settings,
- fakeHandler,)
+ fakeHandler,
+ )
verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
verify(statusBarStateController).addCallback(statusBarCallback.capture())
verify(dreamOverlayStateController).addCallback(dreamOverlayCallback.capture())
@@ -125,7 +126,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
whenever(statusBarStateController.state).thenReturn(StatusBarState.SHADE)
whenever(mediaCarouselController.mediaCarouselScrollHandler)
- .thenReturn(mediaCarouselScrollHandler)
+ .thenReturn(mediaCarouselScrollHandler)
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
observer.onFinishedWakingUp()
@@ -151,30 +152,53 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
fun testBlockedWhenScreenTurningOff() {
// Let's set it onto QS:
mediaHierarchyManager.qsExpansion = 1.0f
- verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
- any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
+ verify(mediaCarouselController)
+ .onDesiredLocationChanged(
+ ArgumentMatchers.anyInt(),
+ any(MediaHostState::class.java),
+ anyBoolean(),
+ anyLong(),
+ anyLong()
+ )
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
observer.onStartedGoingToSleep()
clearInvocations(mediaCarouselController)
mediaHierarchyManager.qsExpansion = 0.0f
verify(mediaCarouselController, times(0))
- .onDesiredLocationChanged(ArgumentMatchers.anyInt(),
- any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
+ .onDesiredLocationChanged(
+ ArgumentMatchers.anyInt(),
+ any(MediaHostState::class.java),
+ anyBoolean(),
+ anyLong(),
+ anyLong()
+ )
}
@Test
fun testAllowedWhenNotTurningOff() {
// Let's set it onto QS:
mediaHierarchyManager.qsExpansion = 1.0f
- verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
- any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
+ verify(mediaCarouselController)
+ .onDesiredLocationChanged(
+ ArgumentMatchers.anyInt(),
+ any(MediaHostState::class.java),
+ anyBoolean(),
+ anyLong(),
+ anyLong()
+ )
val observer = wakefullnessObserver.value
assertNotNull("lifecycle observer wasn't registered", observer)
clearInvocations(mediaCarouselController)
mediaHierarchyManager.qsExpansion = 0.0f
- verify(mediaCarouselController).onDesiredLocationChanged(ArgumentMatchers.anyInt(),
- any(MediaHostState::class.java), anyBoolean(), anyLong(), anyLong())
+ verify(mediaCarouselController)
+ .onDesiredLocationChanged(
+ ArgumentMatchers.anyInt(),
+ any(MediaHostState::class.java),
+ anyBoolean(),
+ anyLong(),
+ anyLong()
+ )
}
@Test
@@ -183,22 +207,26 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
// Let's transition all the way to full shade
mediaHierarchyManager.setTransitionToFullShadeAmount(100000f)
- verify(mediaCarouselController).onDesiredLocationChanged(
- eq(MediaHierarchyManager.LOCATION_QQS),
- any(MediaHostState::class.java),
- eq(false),
- anyLong(),
- anyLong())
+ verify(mediaCarouselController)
+ .onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_QQS),
+ any(MediaHostState::class.java),
+ eq(false),
+ anyLong(),
+ anyLong()
+ )
clearInvocations(mediaCarouselController)
// Let's go back to the lock screen
mediaHierarchyManager.setTransitionToFullShadeAmount(0.0f)
- verify(mediaCarouselController).onDesiredLocationChanged(
- eq(MediaHierarchyManager.LOCATION_LOCKSCREEN),
- any(MediaHostState::class.java),
- eq(false),
- anyLong(),
- anyLong())
+ verify(mediaCarouselController)
+ .onDesiredLocationChanged(
+ eq(MediaHierarchyManager.LOCATION_LOCKSCREEN),
+ any(MediaHostState::class.java),
+ eq(false),
+ anyLong(),
+ anyLong()
+ )
// Let's make sure alpha is set
mediaHierarchyManager.setTransitionToFullShadeAmount(2.0f)
@@ -302,7 +330,7 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
val expectedTranslation = LOCKSCREEN_TOP - QS_TOP
assertThat(mediaHierarchyManager.getGuidedTransformationTranslationY())
- .isEqualTo(expectedTranslation)
+ .isEqualTo(expectedTranslation)
}
@Test
@@ -343,27 +371,31 @@ class MediaHierarchyManagerTest : SysuiTestCase() {
fun testDream() {
goToDream()
setMediaDreamComplicationEnabled(true)
- verify(mediaCarouselController).onDesiredLocationChanged(
+ verify(mediaCarouselController)
+ .onDesiredLocationChanged(
eq(MediaHierarchyManager.LOCATION_DREAM_OVERLAY),
nullable(),
eq(false),
anyLong(),
- anyLong())
+ anyLong()
+ )
clearInvocations(mediaCarouselController)
setMediaDreamComplicationEnabled(false)
- verify(mediaCarouselController).onDesiredLocationChanged(
+ verify(mediaCarouselController)
+ .onDesiredLocationChanged(
eq(MediaHierarchyManager.LOCATION_QQS),
any(MediaHostState::class.java),
eq(false),
anyLong(),
- anyLong())
+ anyLong()
+ )
}
private fun enableSplitShade() {
- context.getOrCreateTestableResources().addOverride(
- R.bool.config_use_split_notification_shade, true
- )
+ context
+ .getOrCreateTestableResources()
+ .addOverride(R.bool.config_use_split_notification_shade, true)
configurationController.notifyConfigurationChanged()
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaPlayerDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaPlayerDataTest.kt
index 9ea8ae9c9bba..32b822d798f8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaPlayerDataTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaPlayerDataTest.kt
@@ -35,13 +35,10 @@ import org.mockito.junit.MockitoJUnit
@RunWith(AndroidTestingRunner::class)
public class MediaPlayerDataTest : SysuiTestCase() {
- @Mock
- private lateinit var playerIsPlaying: MediaControlPanel
+ @Mock private lateinit var playerIsPlaying: MediaControlPanel
private var systemClock: FakeSystemClock = FakeSystemClock()
- @JvmField
- @Rule
- val mockito = MockitoJUnit.rule()
+ @JvmField @Rule val mockito = MockitoJUnit.rule()
companion object {
val LOCAL = MediaData.PLAYBACK_LOCAL
@@ -63,10 +60,20 @@ public class MediaPlayerDataTest : SysuiTestCase() {
val playerIsRemote = mock(MediaControlPanel::class.java)
val dataIsRemote = createMediaData("app2", PLAYING, REMOTE, !RESUMPTION)
- MediaPlayerData.addMediaPlayer("2", dataIsRemote, playerIsRemote, systemClock,
- isSsReactivated = false)
- MediaPlayerData.addMediaPlayer("1", dataIsPlaying, playerIsPlaying, systemClock,
- isSsReactivated = false)
+ MediaPlayerData.addMediaPlayer(
+ "2",
+ dataIsRemote,
+ playerIsRemote,
+ systemClock,
+ isSsReactivated = false
+ )
+ MediaPlayerData.addMediaPlayer(
+ "1",
+ dataIsPlaying,
+ playerIsPlaying,
+ systemClock,
+ isSsReactivated = false
+ )
val players = MediaPlayerData.players()
assertThat(players).hasSize(2)
@@ -81,22 +88,42 @@ public class MediaPlayerDataTest : SysuiTestCase() {
val playerIsPlaying2 = mock(MediaControlPanel::class.java)
var dataIsPlaying2 = createMediaData("app2", !PLAYING, LOCAL, !RESUMPTION)
- MediaPlayerData.addMediaPlayer("1", dataIsPlaying1, playerIsPlaying1, systemClock,
- isSsReactivated = false)
+ MediaPlayerData.addMediaPlayer(
+ "1",
+ dataIsPlaying1,
+ playerIsPlaying1,
+ systemClock,
+ isSsReactivated = false
+ )
systemClock.advanceTime(1)
- MediaPlayerData.addMediaPlayer("2", dataIsPlaying2, playerIsPlaying2, systemClock,
- isSsReactivated = false)
+ MediaPlayerData.addMediaPlayer(
+ "2",
+ dataIsPlaying2,
+ playerIsPlaying2,
+ systemClock,
+ isSsReactivated = false
+ )
systemClock.advanceTime(1)
dataIsPlaying1 = createMediaData("app1", !PLAYING, LOCAL, !RESUMPTION)
dataIsPlaying2 = createMediaData("app2", PLAYING, LOCAL, !RESUMPTION)
- MediaPlayerData.addMediaPlayer("1", dataIsPlaying1, playerIsPlaying1, systemClock,
- isSsReactivated = false)
+ MediaPlayerData.addMediaPlayer(
+ "1",
+ dataIsPlaying1,
+ playerIsPlaying1,
+ systemClock,
+ isSsReactivated = false
+ )
systemClock.advanceTime(1)
- MediaPlayerData.addMediaPlayer("2", dataIsPlaying2, playerIsPlaying2, systemClock,
- isSsReactivated = false)
+ MediaPlayerData.addMediaPlayer(
+ "2",
+ dataIsPlaying2,
+ playerIsPlaying2,
+ systemClock,
+ isSsReactivated = false
+ )
systemClock.advanceTime(1)
val players = MediaPlayerData.players()
@@ -124,26 +151,60 @@ public class MediaPlayerDataTest : SysuiTestCase() {
val dataUndetermined = createMediaData("app6", UNDETERMINED, LOCAL, RESUMPTION)
MediaPlayerData.addMediaPlayer(
- "3", dataIsStoppedAndLocal, playerIsStoppedAndLocal, systemClock,
- isSsReactivated = false)
+ "3",
+ dataIsStoppedAndLocal,
+ playerIsStoppedAndLocal,
+ systemClock,
+ isSsReactivated = false
+ )
MediaPlayerData.addMediaPlayer(
- "5", dataIsStoppedAndRemote, playerIsStoppedAndRemote, systemClock,
- isSsReactivated = false)
- MediaPlayerData.addMediaPlayer("4", dataCanResume, playerCanResume, systemClock,
- isSsReactivated = false)
- MediaPlayerData.addMediaPlayer("1", dataIsPlaying, playerIsPlaying, systemClock,
- isSsReactivated = false)
+ "5",
+ dataIsStoppedAndRemote,
+ playerIsStoppedAndRemote,
+ systemClock,
+ isSsReactivated = false
+ )
MediaPlayerData.addMediaPlayer(
- "2", dataIsPlayingAndRemote, playerIsPlayingAndRemote, systemClock,
- isSsReactivated = false)
- MediaPlayerData.addMediaPlayer("6", dataUndetermined, playerUndetermined, systemClock,
- isSsReactivated = false)
+ "4",
+ dataCanResume,
+ playerCanResume,
+ systemClock,
+ isSsReactivated = false
+ )
+ MediaPlayerData.addMediaPlayer(
+ "1",
+ dataIsPlaying,
+ playerIsPlaying,
+ systemClock,
+ isSsReactivated = false
+ )
+ MediaPlayerData.addMediaPlayer(
+ "2",
+ dataIsPlayingAndRemote,
+ playerIsPlayingAndRemote,
+ systemClock,
+ isSsReactivated = false
+ )
+ MediaPlayerData.addMediaPlayer(
+ "6",
+ dataUndetermined,
+ playerUndetermined,
+ systemClock,
+ isSsReactivated = false
+ )
val players = MediaPlayerData.players()
assertThat(players).hasSize(6)
- assertThat(players).containsExactly(playerIsPlaying, playerIsPlayingAndRemote,
- playerIsStoppedAndRemote, playerIsStoppedAndLocal, playerUndetermined,
- playerCanResume).inOrder()
+ assertThat(players)
+ .containsExactly(
+ playerIsPlaying,
+ playerIsPlayingAndRemote,
+ playerIsStoppedAndRemote,
+ playerIsStoppedAndLocal,
+ playerUndetermined,
+ playerCanResume
+ )
+ .inOrder()
}
@Test
@@ -155,13 +216,23 @@ public class MediaPlayerDataTest : SysuiTestCase() {
assertThat(MediaPlayerData.players()).hasSize(0)
- MediaPlayerData.addMediaPlayer(keyA, data, playerIsPlaying, systemClock,
- isSsReactivated = false)
+ MediaPlayerData.addMediaPlayer(
+ keyA,
+ data,
+ playerIsPlaying,
+ systemClock,
+ isSsReactivated = false
+ )
systemClock.advanceTime(1)
assertThat(MediaPlayerData.players()).hasSize(1)
- MediaPlayerData.addMediaPlayer(keyB, data, playerIsPlaying, systemClock,
- isSsReactivated = false)
+ MediaPlayerData.addMediaPlayer(
+ keyB,
+ data,
+ playerIsPlaying,
+ systemClock,
+ isSsReactivated = false
+ )
systemClock.advanceTime(1)
assertThat(MediaPlayerData.players()).hasSize(2)
@@ -179,12 +250,13 @@ public class MediaPlayerDataTest : SysuiTestCase() {
isPlaying: Boolean?,
location: Int,
resumption: Boolean
- ) = MediaTestUtils.emptyMediaData.copy(
- app = app,
- packageName = "package: $app",
- playbackLocation = location,
- resumption = resumption,
- notificationKey = "key: $app",
- isPlaying = isPlaying
- )
+ ) =
+ MediaTestUtils.emptyMediaData.copy(
+ app = app,
+ packageName = "package: $app",
+ playbackLocation = location,
+ resumption = resumption,
+ notificationKey = "key: $app",
+ isPlaying = isPlaying
+ )
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MetadataAnimationHandlerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MetadataAnimationHandlerTest.kt
index aca35e536424..323b7818ed3d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MetadataAnimationHandlerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MetadataAnimationHandlerTest.kt
@@ -16,7 +16,6 @@
package com.android.systemui.media.controls.ui
-import org.mockito.Mockito.`when` as whenever
import android.animation.Animator
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner
@@ -29,10 +28,11 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.times
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when` as whenever
import org.mockito.junit.MockitoJUnit
@SmallTest
@@ -55,8 +55,7 @@ class MetadataAnimationHandlerTest : SysuiTestCase() {
handler = MetadataAnimationHandler(exitAnimator, enterAnimator)
}
- @After
- fun tearDown() {}
+ @After fun tearDown() {}
@Test
fun firstBind_startsAnimationSet() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/SquigglyProgressTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/SquigglyProgressTest.kt
index aff8992e6266..d6cff81c0aaa 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/SquigglyProgressTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/SquigglyProgressTest.kt
@@ -50,12 +50,9 @@ class SquigglyProgressTest : SysuiTestCase() {
private val tint = Color.GREEN
lateinit var squigglyProgress: SquigglyProgress
- @Mock
- lateinit var canvas: Canvas
- @Captor
- lateinit var paintCaptor: ArgumentCaptor<Paint>
- @JvmField @Rule
- val mockitoRule = MockitoJUnit.rule()
+ @Mock lateinit var canvas: Canvas
+ @Captor lateinit var paintCaptor: ArgumentCaptor<Paint>
+ @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
@Before
fun setup() {
@@ -126,7 +123,6 @@ class SquigglyProgressTest : SysuiTestCase() {
val (wavePaint, linePaint) = paintCaptor.getAllValues()
assertThat(wavePaint.color).isEqualTo(tint)
- assertThat(linePaint.color).isEqualTo(
- ColorUtils.setAlphaComponent(tint, DISABLED_ALPHA))
+ assertThat(linePaint.color).isEqualTo(ColorUtils.setAlphaComponent(tint, DISABLED_ALPHA))
}
-} \ No newline at end of file
+}