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

Commit b5c0f6c6 authored by Caitlin Cassidy's avatar Caitlin Cassidy
Browse files

[Media] Update player's a11y content description based on whether guts

is open or not.

Note: I was hoping that just setting the content description to null if
guts was open would work. When I tried that, it *did* announce "Hide this
control" if I tapped on the player via TalkBack, but it *did not* announce
anything if I used navigation swiping until I was selecting the media
player. So, this code just always sets the description.

Bug: 229574744
Test: manual
Test: MediaControlPanelTest
Change-Id: Ifa69521289a4b7a5cd7a35f092a76827a560e3b1
parent 7ee5bcf8
Loading
Loading
Loading
Loading
+27 −6
Original line number Diff line number Diff line
@@ -448,6 +448,7 @@ public class MediaControlPanel {

        bindOutputSwitcherChip(data);
        bindGutsMenuForPlayer(data);
        bindPlayerContentDescription(data);
        bindScrubbingTime(data);
        bindActionButtons(data);

@@ -541,12 +542,6 @@ public class MediaControlPanel {
    }

    private boolean bindSongMetadata(MediaData data) {
        // Accessibility label
        mMediaViewHolder.getPlayer().setContentDescription(
                mContext.getString(
                        R.string.controls_media_playing_item_description,
                        data.getSong(), data.getArtist(), data.getApp()));

        TextView titleText = mMediaViewHolder.getTitleText();
        TextView artistText = mMediaViewHolder.getArtistText();
        return mMetadataAnimationHandler.setNext(
@@ -568,6 +563,26 @@ public class MediaControlPanel {
            });
    }

    private void bindPlayerContentDescription(MediaData data) {
        if (mMediaViewHolder == null) {
            return;
        }

        CharSequence contentDescription;
        if (mMediaViewController.isGutsVisible()) {
            contentDescription = mMediaViewHolder.getGutsViewHolder().getGutsText().getText();
        } else if (data != null) {
            contentDescription = mContext.getString(
                    R.string.controls_media_playing_item_description,
                    data.getSong(),
                    data.getArtist(),
                    data.getApp());
        } else {
            contentDescription = null;
        }
        mMediaViewHolder.getPlayer().setContentDescription(contentDescription);
    }

    private void bindArtworkAndColors(MediaData data, boolean updateBackground) {
        final int reqId = mArtworkNextBindRequestId++;
        if (updateBackground) {
@@ -1175,6 +1190,9 @@ public class MediaControlPanel {
            mRecommendationViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
        }
        mMediaViewController.closeGuts(immediate);
        if (mMediaViewHolder != null) {
            bindPlayerContentDescription(mMediaData);
        }
    }

    private void closeGuts() {
@@ -1188,6 +1206,9 @@ public class MediaControlPanel {
            mRecommendationViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
        }
        mMediaViewController.openGuts();
        if (mMediaViewHolder != null) {
            bindPlayerContentDescription(mMediaData);
        }
        mLogger.logLongPressOpen(mUid, mPackageName, mInstanceId);
    }

+85 −0
Original line number Diff line number Diff line
@@ -1121,6 +1121,91 @@ public class MediaControlPanelTest : SysuiTestCase() {
        verify(mediaCarouselController).removePlayer(eq(mediaKey), eq(false), eq(false))
    }

    @Test
    fun player_gutsOpen_contentDescriptionIsForGuts() {
        whenever(mediaViewController.isGutsVisible).thenReturn(true)
        player.attachPlayer(viewHolder)

        val gutsTextString = "gutsText"
        whenever(gutsText.text).thenReturn(gutsTextString)
        player.bindPlayer(mediaData, KEY)

        val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
        verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
        val description = descriptionCaptor.value.toString()

        assertThat(description).isEqualTo(gutsTextString)
    }

    @Test
    fun player_gutsClosed_contentDescriptionIsForPlayer() {
        whenever(mediaViewController.isGutsVisible).thenReturn(false)
        player.attachPlayer(viewHolder)

        val app = "appName"
        player.bindPlayer(mediaData.copy(app = app), KEY)

        val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
        verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
        val description = descriptionCaptor.value.toString()

        assertThat(description).contains(mediaData.song!!)
        assertThat(description).contains(mediaData.artist!!)
        assertThat(description).contains(app)
    }

    @Test
    fun player_gutsChangesFromOpenToClosed_contentDescriptionUpdated() {
        // Start out open
        whenever(mediaViewController.isGutsVisible).thenReturn(true)
        whenever(gutsText.text).thenReturn("gutsText")
        player.attachPlayer(viewHolder)
        val app = "appName"
        player.bindPlayer(mediaData.copy(app = app), KEY)

        // Update to closed by long pressing
        val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
        verify(viewHolder.player).onLongClickListener = captor.capture()
        reset(viewHolder.player)

        whenever(mediaViewController.isGutsVisible).thenReturn(false)
        captor.value.onLongClick(viewHolder.player)

        // Then content description is now the player content description
        val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
        verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
        val description = descriptionCaptor.value.toString()

        assertThat(description).contains(mediaData.song!!)
        assertThat(description).contains(mediaData.artist!!)
        assertThat(description).contains(app)
    }

    @Test
    fun player_gutsChangesFromClosedToOpen_contentDescriptionUpdated() {
        // Start out closed
        whenever(mediaViewController.isGutsVisible).thenReturn(false)
        val gutsTextString = "gutsText"
        whenever(gutsText.text).thenReturn(gutsTextString)
        player.attachPlayer(viewHolder)
        player.bindPlayer(mediaData.copy(app = "appName"), KEY)

        // Update to open by long pressing
        val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
        verify(viewHolder.player).onLongClickListener = captor.capture()
        reset(viewHolder.player)

        whenever(mediaViewController.isGutsVisible).thenReturn(true)
        captor.value.onLongClick(viewHolder.player)

        // Then content description is now the guts content description
        val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
        verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
        val description = descriptionCaptor.value.toString()

        assertThat(description).isEqualTo(gutsTextString)
    }

    /* ***** END guts tests for the player ***** */

    /* ***** Guts tests for the recommendations ***** */