Loading packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +1 −1 Original line number Diff line number Diff line Loading @@ -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()); Loading packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt +12 −29 Original line number Diff line number Diff line Loading @@ -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)) } } Loading packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt 0 → 100644 +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)) } } packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt +6 −9 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading Loading
packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +1 −1 Original line number Diff line number Diff line Loading @@ -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()); Loading
packages/SystemUI/src/com/android/systemui/media/SeekBarObserver.kt +12 −29 Original line number Diff line number Diff line Loading @@ -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)) } } Loading
packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt 0 → 100644 +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)) } }
packages/SystemUI/tests/src/com/android/systemui/media/SeekBarObserverTest.kt +6 −9 Original line number Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading