Loading packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt +1 −0 Original line number Diff line number Diff line Loading @@ -61,6 +61,7 @@ class SeekBarObserver(view: View) : Observer<SeekBarViewModel.Progress> { if (!data.enabled) { seekBarView.setEnabled(false) seekBarView.getThumb().setAlpha(0) seekBarView.setProgress(0) elapsedTimeView.setText("") totalTimeView.setText("") return Loading packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt +13 −1 Original line number Diff line number Diff line Loading @@ -77,13 +77,25 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) { 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() val enabled = if (duration != null && duration <= 0) false else true val enabled = if (playbackState == null || playbackState?.getState() == PlaybackState.STATE_NONE || (duration != null && duration <= 0)) false else true _data = Progress(enabled, seekAvailable, position, duration, color) if (shouldPollPlaybackPosition()) { checkPlaybackPosition() } } /** * Puts the seek bar into a resumption state. * * This should be called when the media session behind the controller has been destroyed. */ @AnyThread fun clearController() = bgExecutor.execute { _data = _data.copy(enabled = false) } @AnyThread private fun checkPlaybackPosition(): Runnable = bgExecutor.executeDelayed({ val currentPosition = controller?.playbackState?.position?.toInt() Loading packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java +2 −0 Original line number Diff line number Diff line Loading @@ -170,6 +170,8 @@ public class QSMediaPlayer extends MediaControlPanel { public void clearControls() { super.clearControls(); mSeekBarViewModel.clearController(); View guts = mMediaNotifView.findViewById(R.id.media_guts); View options = mMediaNotifView.findViewById(R.id.qs_media_controls_options); Loading packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt +61 −1 Original line number Diff line number Diff line Loading @@ -86,7 +86,7 @@ public class SeekBarViewModelTest : SysuiTestCase() { } @Test fun updateDuration() { fun updateDurationWithPlayback() { // GIVEN that the duration is contained within the metadata val duration = 12000L val metadata = MediaMetadata.Builder().run { Loading @@ -94,6 +94,12 @@ public class SeekBarViewModelTest : SysuiTestCase() { 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() } whenever(mockController.getPlaybackState()).thenReturn(state) // WHEN the controller is updated viewModel.updateController(mockController, Color.RED) // THEN the duration is extracted Loading @@ -101,6 +107,22 @@ public class SeekBarViewModelTest : SysuiTestCase() { assertThat(viewModel.progress.value!!.enabled).isTrue() } @Test 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() } whenever(mockController.getMetadata()).thenReturn(metadata) // WHEN the controller is updated viewModel.updateController(mockController, Color.RED) // THEN the duration is extracted assertThat(viewModel.progress.value!!.duration).isEqualTo(duration) assertThat(viewModel.progress.value!!.enabled).isFalse() } @Test fun updateDurationNegative() { // GIVEN that the duration is negative Loading @@ -110,6 +132,12 @@ public class SeekBarViewModelTest : SysuiTestCase() { 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() } whenever(mockController.getPlaybackState()).thenReturn(state) // WHEN the controller is updated viewModel.updateController(mockController, Color.RED) // THEN the seek bar is disabled Loading @@ -125,6 +153,12 @@ public class SeekBarViewModelTest : SysuiTestCase() { 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() } whenever(mockController.getPlaybackState()).thenReturn(state) // WHEN the controller is updated viewModel.updateController(mockController, Color.RED) // THEN the seek bar is disabled Loading Loading @@ -372,4 +406,30 @@ public class SeekBarViewModelTest : SysuiTestCase() { // THEN an update task is queued assertThat(fakeExecutor.numPending()).isEqualTo(1) } @Test fun clearSeekBar() { // GIVEN that the duration is contained within the metadata 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() } whenever(mockController.getPlaybackState()).thenReturn(state) // AND the controller has been updated viewModel.updateController(mockController, Color.RED) // WHEN the controller is cleared on the event when the session is destroyed viewModel.clearController() with(fakeExecutor) { advanceClockToNext() runAllReady() } // THEN the seek bar is disabled assertThat(viewModel.progress.value!!.enabled).isFalse() } } Loading
packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt +1 −0 Original line number Diff line number Diff line Loading @@ -61,6 +61,7 @@ class SeekBarObserver(view: View) : Observer<SeekBarViewModel.Progress> { if (!data.enabled) { seekBarView.setEnabled(false) seekBarView.getThumb().setAlpha(0) seekBarView.setProgress(0) elapsedTimeView.setText("") totalTimeView.setText("") return Loading
packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt +13 −1 Original line number Diff line number Diff line Loading @@ -77,13 +77,25 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) { 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() val enabled = if (duration != null && duration <= 0) false else true val enabled = if (playbackState == null || playbackState?.getState() == PlaybackState.STATE_NONE || (duration != null && duration <= 0)) false else true _data = Progress(enabled, seekAvailable, position, duration, color) if (shouldPollPlaybackPosition()) { checkPlaybackPosition() } } /** * Puts the seek bar into a resumption state. * * This should be called when the media session behind the controller has been destroyed. */ @AnyThread fun clearController() = bgExecutor.execute { _data = _data.copy(enabled = false) } @AnyThread private fun checkPlaybackPosition(): Runnable = bgExecutor.executeDelayed({ val currentPosition = controller?.playbackState?.position?.toInt() Loading
packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java +2 −0 Original line number Diff line number Diff line Loading @@ -170,6 +170,8 @@ public class QSMediaPlayer extends MediaControlPanel { public void clearControls() { super.clearControls(); mSeekBarViewModel.clearController(); View guts = mMediaNotifView.findViewById(R.id.media_guts); View options = mMediaNotifView.findViewById(R.id.qs_media_controls_options); Loading
packages/SystemUI/tests/src/com/android/systemui/media/SeekBarViewModelTest.kt +61 −1 Original line number Diff line number Diff line Loading @@ -86,7 +86,7 @@ public class SeekBarViewModelTest : SysuiTestCase() { } @Test fun updateDuration() { fun updateDurationWithPlayback() { // GIVEN that the duration is contained within the metadata val duration = 12000L val metadata = MediaMetadata.Builder().run { Loading @@ -94,6 +94,12 @@ public class SeekBarViewModelTest : SysuiTestCase() { 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() } whenever(mockController.getPlaybackState()).thenReturn(state) // WHEN the controller is updated viewModel.updateController(mockController, Color.RED) // THEN the duration is extracted Loading @@ -101,6 +107,22 @@ public class SeekBarViewModelTest : SysuiTestCase() { assertThat(viewModel.progress.value!!.enabled).isTrue() } @Test 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() } whenever(mockController.getMetadata()).thenReturn(metadata) // WHEN the controller is updated viewModel.updateController(mockController, Color.RED) // THEN the duration is extracted assertThat(viewModel.progress.value!!.duration).isEqualTo(duration) assertThat(viewModel.progress.value!!.enabled).isFalse() } @Test fun updateDurationNegative() { // GIVEN that the duration is negative Loading @@ -110,6 +132,12 @@ public class SeekBarViewModelTest : SysuiTestCase() { 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() } whenever(mockController.getPlaybackState()).thenReturn(state) // WHEN the controller is updated viewModel.updateController(mockController, Color.RED) // THEN the seek bar is disabled Loading @@ -125,6 +153,12 @@ public class SeekBarViewModelTest : SysuiTestCase() { 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() } whenever(mockController.getPlaybackState()).thenReturn(state) // WHEN the controller is updated viewModel.updateController(mockController, Color.RED) // THEN the seek bar is disabled Loading Loading @@ -372,4 +406,30 @@ public class SeekBarViewModelTest : SysuiTestCase() { // THEN an update task is queued assertThat(fakeExecutor.numPending()).isEqualTo(1) } @Test fun clearSeekBar() { // GIVEN that the duration is contained within the metadata 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() } whenever(mockController.getPlaybackState()).thenReturn(state) // AND the controller has been updated viewModel.updateController(mockController, Color.RED) // WHEN the controller is cleared on the event when the session is destroyed viewModel.clearController() with(fakeExecutor) { advanceClockToNext() runAllReady() } // THEN the seek bar is disabled assertThat(viewModel.progress.value!!.enabled).isFalse() } }