Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45be3fb6 authored by Robert Snoeberger's avatar Robert Snoeberger
Browse files

Add test for MediaControlPanel

Bug: 153170704
Test: atest tests/src/com/android/systemui/media/MediaControlPanelTest.kt
Change-Id: I6a163a4d0973e2d3ca5087964435de8fd4ed0bb1
parent b647449d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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());
+12 −29
Original line number Diff line number Diff line
@@ -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))
        }
    }
+203 −0
Original line number Diff line number Diff line
/*
 * 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))
    }
}
+6 −9
Original line number Diff line number Diff line
@@ -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