Merge "Add test for MediaControlPanel" into rvc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
0606dd5670
@@ -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());
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
* <p>Updates the seek bar views in response to changes to the model.
|
||||
*/
|
||||
class SeekBarObserver(view: View) : Observer<SeekBarViewModel.Progress> {
|
||||
|
||||
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<SeekBarViewModel.Progress> {
|
||||
|
||||
/** 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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<MotionScene.Transition> = 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))
|
||||
}
|
||||
}
|
||||
@@ -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<SeekBar>(
|
||||
mockView.findViewById(R.id.media_progress_bar)).thenReturn(seekBarView)
|
||||
whenever<TextView>(
|
||||
mockView.findViewById(R.id.media_elapsed_time)).thenReturn(elapsedTimeView)
|
||||
whenever<TextView>(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
|
||||
|
||||
Reference in New Issue
Block a user