diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 1691c53386d68..aee7a4649d088 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -228,7 +228,7 @@ public class MediaControlPanel {
mLayoutAnimationHelper = new LayoutAnimationHelper(motionView);
GoneChildrenHideHelper.clipGoneChildrenOnLayout(motionView);
mKeyFrames = motionView.getDefinedTransitions().get(0).getKeyFrameList();
- mSeekBarObserver = new SeekBarObserver(motionView);
+ mSeekBarObserver = new SeekBarObserver(vh);
mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
SeekBar bar = vh.getSeekBar();
bar.setOnSeekBarChangeListener(mSeekBarViewModel.getSeekBarListener());
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
index 110b08c4b8085..cd8ed265bd532 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt
@@ -16,58 +16,41 @@
package com.android.systemui.media
-import android.content.res.ColorStateList
-import android.graphics.Color
import android.text.format.DateUtils
-import android.view.View
-import android.widget.SeekBar
-import android.widget.TextView
import androidx.annotation.UiThread
import androidx.lifecycle.Observer
-import com.android.systemui.R
-
/**
* Observer for changes from SeekBarViewModel.
*
*
Updates the seek bar views in response to changes to the model.
*/
-class SeekBarObserver(view: View) : Observer {
-
- private val seekBarView: SeekBar
- private val elapsedTimeView: TextView
- private val totalTimeView: TextView
-
- init {
- seekBarView = view.findViewById(R.id.media_progress_bar)
- elapsedTimeView = view.findViewById(R.id.media_elapsed_time)
- totalTimeView = view.findViewById(R.id.media_total_time)
- }
+class SeekBarObserver(private val holder: PlayerViewHolder) : Observer {
/** Updates seek bar views when the data model changes. */
@UiThread
override fun onChanged(data: SeekBarViewModel.Progress) {
if (!data.enabled) {
- seekBarView.setEnabled(false)
- seekBarView.getThumb().setAlpha(0)
- seekBarView.setProgress(0)
- elapsedTimeView.setText("")
- totalTimeView.setText("")
+ holder.seekBar.setEnabled(false)
+ holder.seekBar.getThumb().setAlpha(0)
+ holder.seekBar.setProgress(0)
+ holder.elapsedTimeView.setText("")
+ holder.totalTimeView.setText("")
return
}
- seekBarView.getThumb().setAlpha(if (data.seekAvailable) 255 else 0)
- seekBarView.setEnabled(data.seekAvailable)
+ holder.seekBar.getThumb().setAlpha(if (data.seekAvailable) 255 else 0)
+ holder.seekBar.setEnabled(data.seekAvailable)
data.elapsedTime?.let {
- seekBarView.setProgress(it)
- elapsedTimeView.setText(DateUtils.formatElapsedTime(
+ holder.seekBar.setProgress(it)
+ holder.elapsedTimeView.setText(DateUtils.formatElapsedTime(
it / DateUtils.SECOND_IN_MILLIS))
}
data.duration?.let {
- seekBarView.setMax(it)
- totalTimeView.setText(DateUtils.formatElapsedTime(
+ holder.seekBar.setMax(it)
+ holder.totalTimeView.setText(DateUtils.formatElapsedTime(
it / DateUtils.SECOND_IN_MILLIS))
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
new file mode 100644
index 0000000000000..60d15a8fb480b
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2020 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
+
+import android.content.res.ColorStateList
+import android.graphics.Color
+import android.media.MediaMetadata
+import android.media.session.MediaSession
+import android.media.session.PlaybackState
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import android.widget.ImageButton
+import android.widget.ImageView
+import android.widget.SeekBar
+import android.widget.TextView
+
+import androidx.constraintlayout.motion.widget.MotionLayout
+import androidx.constraintlayout.motion.widget.MotionScene
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.test.filters.SmallTest
+
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+
+import com.google.common.truth.Truth.assertThat
+
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.`when` as whenever
+
+import java.util.ArrayList
+
+private const val KEY = "TEST_KEY"
+private const val APP = "APP"
+private const val BG_COLOR = Color.RED
+private const val PACKAGE = "PKG"
+private const val ARTIST = "ARTIST"
+private const val TITLE = "TITLE"
+private const val DEVICE_NAME = "DEVICE_NAME"
+private const val SESSION_KEY = "SESSION_KEY"
+private const val SESSION_ARTIST = "SESSION_ARTIST"
+private const val SESSION_TITLE = "SESSION_TITLE"
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class MediaControlPanelTest : SysuiTestCase() {
+
+ private lateinit var player: MediaControlPanel
+
+ private lateinit var fgExecutor: FakeExecutor
+ private lateinit var bgExecutor: FakeExecutor
+ @Mock private lateinit var activityStarter: ActivityStarter
+
+ @Mock private lateinit var holder: PlayerViewHolder
+ @Mock private lateinit var motion: MotionLayout
+ private lateinit var background: TextView
+ private lateinit var appIcon: ImageView
+ private lateinit var appName: TextView
+ private lateinit var albumView: ImageView
+ private lateinit var titleText: TextView
+ private lateinit var artistText: TextView
+ private lateinit var seamless: ViewGroup
+ private lateinit var seamlessIcon: ImageView
+ private lateinit var seamlessText: TextView
+ private lateinit var seekBar: SeekBar
+ private lateinit var elapsedTimeView: TextView
+ private lateinit var totalTimeView: TextView
+ private lateinit var action0: ImageButton
+ private lateinit var action1: ImageButton
+ private lateinit var action2: ImageButton
+ private lateinit var action3: ImageButton
+ private lateinit var action4: ImageButton
+
+ private lateinit var session: MediaSession
+
+ @Before
+ fun setUp() {
+ fgExecutor = FakeExecutor(FakeSystemClock())
+ bgExecutor = FakeExecutor(FakeSystemClock())
+
+ activityStarter = mock(ActivityStarter::class.java)
+
+ player = MediaControlPanel(context, null, fgExecutor, bgExecutor, activityStarter)
+
+ // Mock out a view holder for the player to attach to.
+ holder = mock(PlayerViewHolder::class.java)
+ motion = mock(MotionLayout::class.java)
+ val trans: ArrayList = ArrayList()
+ trans.add(mock(MotionScene.Transition::class.java))
+ whenever(motion.definedTransitions).thenReturn(trans)
+ val constraintSet = mock(ConstraintSet::class.java)
+ whenever(motion.getConstraintSet(R.id.expanded)).thenReturn(constraintSet)
+ whenever(motion.getConstraintSet(R.id.collapsed)).thenReturn(constraintSet)
+ whenever(holder.player).thenReturn(motion)
+ background = TextView(context)
+ whenever(holder.background).thenReturn(background)
+ appIcon = ImageView(context)
+ whenever(holder.appIcon).thenReturn(appIcon)
+ appName = TextView(context)
+ whenever(holder.appName).thenReturn(appName)
+ albumView = ImageView(context)
+ whenever(holder.albumView).thenReturn(albumView)
+ titleText = TextView(context)
+ whenever(holder.titleText).thenReturn(titleText)
+ artistText = TextView(context)
+ whenever(holder.artistText).thenReturn(artistText)
+ seamless = FrameLayout(context)
+ whenever(holder.seamless).thenReturn(seamless)
+ seamlessIcon = ImageView(context)
+ whenever(holder.seamlessIcon).thenReturn(seamlessIcon)
+ seamlessText = TextView(context)
+ whenever(holder.seamlessText).thenReturn(seamlessText)
+ seekBar = SeekBar(context)
+ whenever(holder.seekBar).thenReturn(seekBar)
+ elapsedTimeView = TextView(context)
+ whenever(holder.elapsedTimeView).thenReturn(elapsedTimeView)
+ totalTimeView = TextView(context)
+ whenever(holder.totalTimeView).thenReturn(totalTimeView)
+ action0 = ImageButton(context)
+ whenever(holder.action0).thenReturn(action0)
+ action1 = ImageButton(context)
+ whenever(holder.action1).thenReturn(action1)
+ action2 = ImageButton(context)
+ whenever(holder.action2).thenReturn(action2)
+ action3 = ImageButton(context)
+ whenever(holder.action3).thenReturn(action3)
+ action4 = ImageButton(context)
+ whenever(holder.action4).thenReturn(action4)
+
+ // 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())
+ }
+ session.setActive(true)
+ }
+
+ @After
+ fun tearDown() {
+ session.release()
+ player.onDestroy()
+ }
+
+ @Test
+ fun bindWhenUnattached() {
+ val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
+ emptyList(), PACKAGE, null, null)
+ player.bind(state)
+ assertThat(player.isPlaying()).isFalse()
+ }
+
+ @Test
+ fun bindText() {
+ player.attach(holder)
+ val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
+ emptyList(), PACKAGE, session.getSessionToken(), null)
+ player.bind(state)
+ assertThat(appName.getText()).isEqualTo(APP)
+ assertThat(titleText.getText()).isEqualTo(TITLE)
+ assertThat(artistText.getText()).isEqualTo(ARTIST)
+ }
+
+ @Test
+ fun bindBackgroundColor() {
+ player.attach(holder)
+ val state = MediaData(true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
+ emptyList(), PACKAGE, session.getSessionToken(), null)
+ player.bind(state)
+ assertThat(background.getBackgroundTintList()).isEqualTo(ColorStateList.valueOf(BG_COLOR))
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
index 58ee79e39279c..75018df023cc1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt
@@ -22,7 +22,6 @@ import android.view.View
import android.widget.SeekBar
import android.widget.TextView
import androidx.test.filters.SmallTest
-import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -38,23 +37,21 @@ import org.mockito.Mockito.`when` as whenever
public class SeekBarObserverTest : SysuiTestCase() {
private lateinit var observer: SeekBarObserver
- @Mock private lateinit var mockView: View
+ @Mock private lateinit var mockHolder: PlayerViewHolder
private lateinit var seekBarView: SeekBar
private lateinit var elapsedTimeView: TextView
private lateinit var totalTimeView: TextView
@Before
fun setUp() {
- mockView = mock(View::class.java)
+ mockHolder = mock(PlayerViewHolder::class.java)
seekBarView = SeekBar(context)
elapsedTimeView = TextView(context)
totalTimeView = TextView(context)
- whenever(
- mockView.findViewById(R.id.media_progress_bar)).thenReturn(seekBarView)
- whenever(
- mockView.findViewById(R.id.media_elapsed_time)).thenReturn(elapsedTimeView)
- whenever(mockView.findViewById(R.id.media_total_time)).thenReturn(totalTimeView)
- observer = SeekBarObserver(mockView)
+ whenever(mockHolder.seekBar).thenReturn(seekBarView)
+ whenever(mockHolder.elapsedTimeView).thenReturn(elapsedTimeView)
+ whenever(mockHolder.totalTimeView).thenReturn(totalTimeView)
+ observer = SeekBarObserver(mockHolder)
}
@Test