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

Commit 8155e761 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge changes I4f49bb96,I8c8ee829 into tm-dev am: 0423dff2

parents a54c615b 0423dff2
Loading
Loading
Loading
Loading
+19 −41
Original line number Original line Diff line number Diff line
@@ -18,6 +18,8 @@ package com.android.systemui.media;


import static android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS;
import static android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS;


import static com.android.systemui.media.SmartspaceMediaDataKt.NUM_REQUIRED_RECOMMENDATIONS;

import android.animation.Animator;
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.animation.AnimatorSet;
@@ -102,7 +104,6 @@ public class MediaControlPanel {
            + ".android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity";
            + ".android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity";
    private static final String EXTRAS_SMARTSPACE_INTENT =
    private static final String EXTRAS_SMARTSPACE_INTENT =
            "com.google.android.apps.gsa.smartspace.extra.SMARTSPACE_INTENT";
            "com.google.android.apps.gsa.smartspace.extra.SMARTSPACE_INTENT";
    private static final int MEDIA_RECOMMENDATION_MAX_NUM = 3;
    private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name";
    private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name";
    private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";
    private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";
    private static final String KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME";
    private static final String KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME";
@@ -949,16 +950,14 @@ public class MediaControlPanel {
            return;
            return;
        }
        }


        if (!data.isValid()) {
            Log.e(TAG, "Received an invalid recommendation list; returning");
            return;
        }

        mSmartspaceId = SmallHash.hash(data.getTargetId());
        mSmartspaceId = SmallHash.hash(data.getTargetId());
        mPackageName = data.getPackageName();
        mPackageName = data.getPackageName();
        mInstanceId = data.getInstanceId();
        mInstanceId = data.getInstanceId();
        TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations();

        List<SmartspaceAction> mediaRecommendationList = data.getRecommendations();
        if (mediaRecommendationList == null || mediaRecommendationList.isEmpty()) {
            Log.w(TAG, "Empty media recommendations");
            return;
        }


        // Set up recommendation card's header.
        // Set up recommendation card's header.
        ApplicationInfo applicationInfo;
        ApplicationInfo applicationInfo;
@@ -994,6 +993,7 @@ public class MediaControlPanel {
        }
        }


        // Set up media rec card's tap action if applicable.
        // Set up media rec card's tap action if applicable.
        TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations();
        setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(),
        setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(),
                /* interactedSubcardRank */ -1);
                /* interactedSubcardRank */ -1);
        // Set up media rec card's accessibility label.
        // Set up media rec card's accessibility label.
@@ -1002,29 +1002,20 @@ public class MediaControlPanel {


        List<ImageView> mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems();
        List<ImageView> mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems();
        List<ViewGroup> mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers();
        List<ViewGroup> mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers();
        int mediaRecommendationNum = Math.min(mediaRecommendationList.size(),
        List<SmartspaceAction> recommendations = data.getValidRecommendations();
                MEDIA_RECOMMENDATION_MAX_NUM);


        boolean hasTitle = false;
        boolean hasTitle = false;
        boolean hasSubtitle = false;
        boolean hasSubtitle = false;
        int uiComponentIndex = 0;
        for (int itemIndex = 0; itemIndex < NUM_REQUIRED_RECOMMENDATIONS; itemIndex++) {
        for (int itemIndex = 0;
            SmartspaceAction recommendation = recommendations.get(itemIndex);
                itemIndex < mediaRecommendationNum && uiComponentIndex < mediaRecommendationNum;
                itemIndex++) {
            SmartspaceAction recommendation = mediaRecommendationList.get(itemIndex);
            if (recommendation.getIcon() == null) {
                Log.w(TAG, "No media cover is provided. Skipping this item...");
                continue;
            }


            // Set up media item cover.
            // Set up media item cover.
            ImageView mediaCoverImageView = mediaCoverItems.get(uiComponentIndex);
            ImageView mediaCoverImageView = mediaCoverItems.get(itemIndex);
            mediaCoverImageView.setImageIcon(recommendation.getIcon());
            mediaCoverImageView.setImageIcon(recommendation.getIcon());


            // Set up the media item's click listener if applicable.
            // Set up the media item's click listener if applicable.
            ViewGroup mediaCoverContainer = mediaCoverContainers.get(uiComponentIndex);
            ViewGroup mediaCoverContainer = mediaCoverContainers.get(itemIndex);
            setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation,
            setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation, itemIndex);
                    uiComponentIndex);
            // Bubble up the long-click event to the card.
            // Bubble up the long-click event to the card.
            mediaCoverContainer.setOnLongClickListener(v -> {
            mediaCoverContainer.setOnLongClickListener(v -> {
                View parent = (View) v.getParent();
                View parent = (View) v.getParent();
@@ -1053,8 +1044,7 @@ public class MediaControlPanel {
            // Set up title
            // Set up title
            CharSequence title = recommendation.getTitle();
            CharSequence title = recommendation.getTitle();
            hasTitle |= !TextUtils.isEmpty(title);
            hasTitle |= !TextUtils.isEmpty(title);
            TextView titleView =
            TextView titleView = mRecommendationViewHolder.getMediaTitles().get(itemIndex);
                    mRecommendationViewHolder.getMediaTitles().get(uiComponentIndex);
            titleView.setText(title);
            titleView.setText(title);


            // Set up subtitle
            // Set up subtitle
@@ -1062,13 +1052,10 @@ public class MediaControlPanel {
            boolean shouldShowSubtitleText = !TextUtils.isEmpty(title);
            boolean shouldShowSubtitleText = !TextUtils.isEmpty(title);
            CharSequence subtitle = shouldShowSubtitleText ? recommendation.getSubtitle() : "";
            CharSequence subtitle = shouldShowSubtitleText ? recommendation.getSubtitle() : "";
            hasSubtitle |= !TextUtils.isEmpty(subtitle);
            hasSubtitle |= !TextUtils.isEmpty(subtitle);
            TextView subtitleView =
            TextView subtitleView = mRecommendationViewHolder.getMediaSubtitles().get(itemIndex);
                    mRecommendationViewHolder.getMediaSubtitles().get(uiComponentIndex);
            subtitleView.setText(subtitle);
            subtitleView.setText(subtitle);

            uiComponentIndex++;
        }
        }
        mSmartspaceMediaItemsCount = uiComponentIndex;
        mSmartspaceMediaItemsCount = NUM_REQUIRED_RECOMMENDATIONS;


        // If there's no subtitles and/or titles for any of the albums, hide those views.
        // If there's no subtitles and/or titles for any of the albums, hide those views.
        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
@@ -1301,7 +1288,7 @@ public class MediaControlPanel {
            }
            }
            logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
            logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
                    interactedSubcardRank,
                    interactedSubcardRank,
                    getSmartspaceSubCardCardinality());
                    mSmartspaceMediaItemsCount);


            if (shouldSmartspaceRecItemOpenInForeground(action)) {
            if (shouldSmartspaceRecItemOpenInForeground(action)) {
                // Request to unlock the device if the activity needs to be opened in foreground.
                // Request to unlock the device if the activity needs to be opened in foreground.
@@ -1386,13 +1373,4 @@ public class MediaControlPanel {
                interactedSubcardRank,
                interactedSubcardRank,
                interactedSubcardCardinality);
                interactedSubcardCardinality);
    }
    }

    private int getSmartspaceSubCardCardinality() {
        if (!mMediaCarouselController.getMediaCarouselScrollHandler().getQsExpanded()
                && mSmartspaceMediaItemsCount > 3) {
            return 3;
        }

        return mSmartspaceMediaItemsCount;
    }
}
}
+3 −5
Original line number Original line Diff line number Diff line
@@ -166,7 +166,7 @@ class MediaDataFilter @Inject constructor(
            shouldPrioritizeMutable = true
            shouldPrioritizeMutable = true
        }
        }


        if (!data.isValid) {
        if (!data.isValid()) {
            Log.d(TAG, "Invalid recommendation data. Skip showing the rec card")
            Log.d(TAG, "Invalid recommendation data. Skip showing the rec card")
            return
            return
        }
        }
@@ -203,7 +203,6 @@ class MediaDataFilter @Inject constructor(
        if (smartspaceMediaData.isActive) {
        if (smartspaceMediaData.isActive) {
            smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
            smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
                targetId = smartspaceMediaData.targetId,
                targetId = smartspaceMediaData.targetId,
                isValid = smartspaceMediaData.isValid,
                instanceId = smartspaceMediaData.instanceId)
                instanceId = smartspaceMediaData.instanceId)
        }
        }
        listeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
        listeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
@@ -260,7 +259,6 @@ class MediaDataFilter @Inject constructor(
            }
            }
            smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
            smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
                targetId = smartspaceMediaData.targetId,
                targetId = smartspaceMediaData.targetId,
                isValid = smartspaceMediaData.isValid,
                instanceId = smartspaceMediaData.instanceId)
                instanceId = smartspaceMediaData.instanceId)
            mediaDataManager.dismissSmartspaceRecommendation(smartspaceMediaData.targetId,
            mediaDataManager.dismissSmartspaceRecommendation(smartspaceMediaData.targetId,
                delay = 0L)
                delay = 0L)
@@ -272,13 +270,13 @@ class MediaDataFilter @Inject constructor(
     */
     */
    fun hasActiveMediaOrRecommendation() =
    fun hasActiveMediaOrRecommendation() =
            userEntries.any { it.value.active } ||
            userEntries.any { it.value.active } ||
                    (smartspaceMediaData.isActive && smartspaceMediaData.isValid)
                    (smartspaceMediaData.isActive && smartspaceMediaData.isValid())


    /**
    /**
     * Are there any media entries we should display?
     * Are there any media entries we should display?
     */
     */
    fun hasAnyMediaOrRecommendation() = userEntries.isNotEmpty() ||
    fun hasAnyMediaOrRecommendation() = userEntries.isNotEmpty() ||
            (smartspaceMediaData.isActive && smartspaceMediaData.isValid)
            (smartspaceMediaData.isActive && smartspaceMediaData.isValid())


    /**
    /**
     * Are there any media notifications active (excluding the recommendation)?
     * Are there any media notifications active (excluding the recommendation)?
+1 −3
Original line number Original line Diff line number Diff line
@@ -105,7 +105,6 @@ private val LOADING = MediaData(
internal val EMPTY_SMARTSPACE_MEDIA_DATA = SmartspaceMediaData(
internal val EMPTY_SMARTSPACE_MEDIA_DATA = SmartspaceMediaData(
    targetId = "INVALID",
    targetId = "INVALID",
    isActive = false,
    isActive = false,
    isValid = false,
    packageName = "INVALID",
    packageName = "INVALID",
    cardAction = null,
    cardAction = null,
    recommendations = emptyList(),
    recommendations = emptyList(),
@@ -551,7 +550,7 @@ class MediaDataManager(
     * connection session.
     * connection session.
     */
     */
    fun dismissSmartspaceRecommendation(key: String, delay: Long) {
    fun dismissSmartspaceRecommendation(key: String, delay: Long) {
        if (smartspaceMediaData.targetId != key || !smartspaceMediaData.isValid) {
        if (smartspaceMediaData.targetId != key || !smartspaceMediaData.isValid()) {
            // If this doesn't match, or we've already invalidated the data, no action needed
            // If this doesn't match, or we've already invalidated the data, no action needed
            return
            return
        }
        }
@@ -1240,7 +1239,6 @@ class MediaDataManager(
            return SmartspaceMediaData(
            return SmartspaceMediaData(
                targetId = target.smartspaceTargetId,
                targetId = target.smartspaceTargetId,
                isActive = isActive,
                isActive = isActive,
                isValid = true,
                packageName = it,
                packageName = it,
                cardAction = target.baseAction,
                cardAction = target.baseAction,
                recommendations = target.iconGrid,
                recommendations = target.iconGrid,
+16 −5
Original line number Original line Diff line number Diff line
@@ -30,10 +30,6 @@ data class SmartspaceMediaData(
     * Indicates if the status is active.
     * Indicates if the status is active.
     */
     */
    val isActive: Boolean,
    val isActive: Boolean,
    /**
     * Indicates if all the required data field is valid.
     */
    val isValid: Boolean,
    /**
    /**
     * Package name of the media recommendations' provider-app.
     * Package name of the media recommendations' provider-app.
     */
     */
@@ -58,4 +54,19 @@ data class SmartspaceMediaData(
     * Instance ID for [MediaUiEventLogger]
     * Instance ID for [MediaUiEventLogger]
     */
     */
    val instanceId: InstanceId
    val instanceId: InstanceId
)
) {
    /**
     * Indicates if all the data is valid.
     *
     * TODO(b/230333302): Make MediaControlPanel more flexible so that we can display fewer than
     *     [NUM_REQUIRED_RECOMMENDATIONS].
     */
    fun isValid() = getValidRecommendations().size >= NUM_REQUIRED_RECOMMENDATIONS

    /**
     * Returns the list of [recommendations] that have valid data.
     */
    fun getValidRecommendations() = recommendations.filter { it.icon != null }
}

const val NUM_REQUIRED_RECOMMENDATIONS = 3
+61 −5
Original line number Original line Diff line number Diff line
@@ -124,7 +124,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
    @Mock private lateinit var collapsedSet: ConstraintSet
    @Mock private lateinit var collapsedSet: ConstraintSet
    @Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory
    @Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory
    @Mock private lateinit var mediaCarouselController: MediaCarouselController
    @Mock private lateinit var mediaCarouselController: MediaCarouselController
    @Mock private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
    @Mock private lateinit var falsingManager: FalsingManager
    @Mock private lateinit var falsingManager: FalsingManager
    @Mock private lateinit var transitionParent: ViewGroup
    @Mock private lateinit var transitionParent: ViewGroup
    private lateinit var appIcon: ImageView
    private lateinit var appIcon: ImageView
@@ -270,7 +269,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
        smartspaceData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
        smartspaceData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
            packageName = PACKAGE,
            packageName = PACKAGE,
            instanceId = instanceId,
            instanceId = instanceId,
            recommendations = listOf(smartspaceAction),
            recommendations = listOf(smartspaceAction, smartspaceAction, smartspaceAction),
            cardAction = smartspaceAction
            cardAction = smartspaceAction
        )
        )
    }
    }
@@ -294,9 +293,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
     */
     */
    private fun initMediaViewHolderMocks() {
    private fun initMediaViewHolderMocks() {
        whenever(seekBarViewModel.progress).thenReturn(seekBarData)
        whenever(seekBarViewModel.progress).thenReturn(seekBarData)
        whenever(mediaCarouselController.mediaCarouselScrollHandler)
            .thenReturn(mediaCarouselScrollHandler)
        whenever(mediaCarouselScrollHandler.qsExpanded).thenReturn(false)


        // Set up mock views for the players
        // Set up mock views for the players
        appIcon = ImageView(context)
        appIcon = ImageView(context)
@@ -1447,6 +1443,66 @@ public class MediaControlPanelTest : SysuiTestCase() {
        verify(logger).logRecommendationItemTap(eq(PACKAGE), eq(instanceId), eq(0))
        verify(logger).logRecommendationItemTap(eq(PACKAGE), eq(instanceId), eq(0))
    }
    }


    @Test
    fun bindRecommendation_listHasTooFewRecs_notDisplayed() {
        player.attachRecommendation(recommendationViewHolder)
        val icon = Icon.createWithResource(context, R.drawable.ic_1x_mobiledata)
        val data = smartspaceData.copy(
            recommendations = listOf(
                SmartspaceAction.Builder("id1", "title1")
                    .setSubtitle("subtitle1")
                    .setIcon(icon)
                    .setExtras(Bundle.EMPTY)
                    .build(),
                SmartspaceAction.Builder("id2", "title2")
                    .setSubtitle("subtitle2")
                    .setIcon(icon)
                    .setExtras(Bundle.EMPTY)
                    .build(),
            )
        )

        player.bindRecommendation(data)

        assertThat(recTitle1.text).isEqualTo("")
        verify(mediaViewController, never()).refreshState()
    }

    @Test
    fun bindRecommendation_listHasTooFewRecsWithIcons_notDisplayed() {
        player.attachRecommendation(recommendationViewHolder)
        val icon = Icon.createWithResource(context, R.drawable.ic_1x_mobiledata)
        val data = smartspaceData.copy(
            recommendations = listOf(
                SmartspaceAction.Builder("id1", "title1")
                    .setSubtitle("subtitle1")
                    .setIcon(icon)
                    .setExtras(Bundle.EMPTY)
                    .build(),
                SmartspaceAction.Builder("id2", "title2")
                    .setSubtitle("subtitle2")
                    .setIcon(icon)
                    .setExtras(Bundle.EMPTY)
                    .build(),
                SmartspaceAction.Builder("id2", "empty icon 1")
                    .setSubtitle("subtitle2")
                    .setIcon(null)
                    .setExtras(Bundle.EMPTY)
                    .build(),
                SmartspaceAction.Builder("id2", "empty icon 2")
                    .setSubtitle("subtitle2")
                    .setIcon(null)
                    .setExtras(Bundle.EMPTY)
                    .build(),
            )
        )

        player.bindRecommendation(data)

        assertThat(recTitle1.text).isEqualTo("")
        verify(mediaViewController, never()).refreshState()
    }

    @Test
    @Test
    fun bindRecommendation_hasTitlesAndSubtitles() {
    fun bindRecommendation_hasTitlesAndSubtitles() {
        player.attachRecommendation(recommendationViewHolder)
        player.attachRecommendation(recommendationViewHolder)
Loading