Merge changes I4f49bb96,I8c8ee829 into tm-dev am: 0423dff207
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17988653 Change-Id: Iac225e5b15e1f8ee1872d3196ef71b8b093fd807 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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)?
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ class MediaDataFilterTest : SysuiTestCase() {
|
|||||||
|
|
||||||
`when`(smartspaceData.targetId).thenReturn(SMARTSPACE_KEY)
|
`when`(smartspaceData.targetId).thenReturn(SMARTSPACE_KEY)
|
||||||
`when`(smartspaceData.isActive).thenReturn(true)
|
`when`(smartspaceData.isActive).thenReturn(true)
|
||||||
`when`(smartspaceData.isValid).thenReturn(true)
|
`when`(smartspaceData.isValid()).thenReturn(true)
|
||||||
`when`(smartspaceData.packageName).thenReturn(SMARTSPACE_PACKAGE)
|
`when`(smartspaceData.packageName).thenReturn(SMARTSPACE_PACKAGE)
|
||||||
`when`(smartspaceData.recommendations).thenReturn(listOf(smartspaceMediaRecommendationItem))
|
`when`(smartspaceData.recommendations).thenReturn(listOf(smartspaceMediaRecommendationItem))
|
||||||
`when`(smartspaceData.headphoneConnectionTimeMillis).thenReturn(
|
`when`(smartspaceData.headphoneConnectionTimeMillis).thenReturn(
|
||||||
@@ -196,24 +196,110 @@ class MediaDataFilterTest : SysuiTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testHasAnyMediaOrRecommendation() {
|
fun hasAnyMedia_noMediaSet_returnsFalse() {
|
||||||
assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isFalse()
|
assertThat(mediaDataFilter.hasAnyMedia()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasAnyMedia_mediaSet_returnsTrue() {
|
||||||
mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain)
|
mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain)
|
||||||
assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isTrue()
|
|
||||||
assertThat(mediaDataFilter.hasAnyMedia()).isTrue()
|
assertThat(mediaDataFilter.hasAnyMedia()).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testHasActiveMediaOrRecommendation() {
|
fun hasAnyMedia_recommendationSet_returnsFalse() {
|
||||||
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
|
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
|
||||||
val data = dataMain.copy(active = true)
|
|
||||||
|
|
||||||
|
assertThat(mediaDataFilter.hasAnyMedia()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasAnyMediaOrRecommendation_noMediaSet_returnsFalse() {
|
||||||
|
assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasAnyMediaOrRecommendation_mediaSet_returnsTrue() {
|
||||||
|
mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = dataMain)
|
||||||
|
|
||||||
|
assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasAnyMediaOrRecommendation_recommendationSet_returnsTrue() {
|
||||||
|
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
|
||||||
|
|
||||||
|
assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasActiveMedia_noMediaSet_returnsFalse() {
|
||||||
|
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasActiveMedia_inactiveMediaSet_returnsFalse() {
|
||||||
|
val data = dataMain.copy(active = false)
|
||||||
mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data)
|
mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data)
|
||||||
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue()
|
|
||||||
|
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasActiveMedia_activeMediaSet_returnsTrue() {
|
||||||
|
val data = dataMain.copy(active = true)
|
||||||
|
mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data)
|
||||||
|
|
||||||
assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
|
assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasActiveMediaOrRecommendation_nothingSet_returnsFalse() {
|
||||||
|
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasActiveMediaOrRecommendation_inactiveMediaSet_returnsFalse() {
|
||||||
|
val data = dataMain.copy(active = false)
|
||||||
|
mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data)
|
||||||
|
|
||||||
|
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasActiveMediaOrRecommendation_activeMediaSet_returnsTrue() {
|
||||||
|
val data = dataMain.copy(active = true)
|
||||||
|
mediaDataFilter.onMediaDataLoaded(KEY, oldKey = null, data = data)
|
||||||
|
|
||||||
|
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasActiveMediaOrRecommendation_inactiveRecommendationSet_returnsFalse() {
|
||||||
|
`when`(smartspaceData.isActive).thenReturn(false)
|
||||||
|
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
|
||||||
|
|
||||||
|
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasActiveMediaOrRecommendation_invalidRecommendationSet_returnsFalse() {
|
||||||
|
`when`(smartspaceData.isValid()).thenReturn(false)
|
||||||
|
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
|
||||||
|
|
||||||
|
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun hasActiveMediaOrRecommendation_activeAndValidRecommendationSet_returnsTrue() {
|
||||||
|
`when`(smartspaceData.isActive).thenReturn(true)
|
||||||
|
`when`(smartspaceData.isValid()).thenReturn(true)
|
||||||
|
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
|
||||||
|
|
||||||
|
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testHasAnyMediaOrRecommendation_onlyCurrentUser() {
|
fun testHasAnyMediaOrRecommendation_onlyCurrentUser() {
|
||||||
assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isFalse()
|
assertThat(mediaDataFilter.hasAnyMediaOrRecommendation()).isFalse()
|
||||||
@@ -332,7 +418,7 @@ class MediaDataFilterTest : SysuiTestCase() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_activeInvalidRec_usesMedia() {
|
fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_activeInvalidRec_usesMedia() {
|
||||||
`when`(smartspaceData.isValid).thenReturn(false)
|
`when`(smartspaceData.isValid()).thenReturn(false)
|
||||||
|
|
||||||
// WHEN we have media that was recently played, but not currently active
|
// WHEN we have media that was recently played, but not currently active
|
||||||
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
|
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import android.app.smartspace.SmartspaceAction
|
|||||||
import android.app.smartspace.SmartspaceTarget
|
import android.app.smartspace.SmartspaceTarget
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.drawable.Icon
|
||||||
import android.media.MediaDescription
|
import android.media.MediaDescription
|
||||||
import android.media.MediaMetadata
|
import android.media.MediaMetadata
|
||||||
import android.media.session.MediaController
|
import android.media.session.MediaController
|
||||||
@@ -97,6 +98,7 @@ class MediaDataManagerTest : SysuiTestCase() {
|
|||||||
lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
|
lateinit var smartspaceMediaDataProvider: SmartspaceMediaDataProvider
|
||||||
@Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget
|
@Mock lateinit var mediaSmartspaceTarget: SmartspaceTarget
|
||||||
@Mock private lateinit var mediaRecommendationItem: SmartspaceAction
|
@Mock private lateinit var mediaRecommendationItem: SmartspaceAction
|
||||||
|
lateinit var validRecommendationList: List<SmartspaceAction>
|
||||||
@Mock private lateinit var mediaSmartspaceBaseAction: SmartspaceAction
|
@Mock private lateinit var mediaSmartspaceBaseAction: SmartspaceAction
|
||||||
@Mock private lateinit var mediaFlags: MediaFlags
|
@Mock private lateinit var mediaFlags: MediaFlags
|
||||||
@Mock private lateinit var logger: MediaUiEventLogger
|
@Mock private lateinit var logger: MediaUiEventLogger
|
||||||
@@ -172,12 +174,17 @@ class MediaDataManagerTest : SysuiTestCase() {
|
|||||||
putString("package_name", PACKAGE_NAME)
|
putString("package_name", PACKAGE_NAME)
|
||||||
putParcelable("dismiss_intent", DISMISS_INTENT)
|
putParcelable("dismiss_intent", DISMISS_INTENT)
|
||||||
}
|
}
|
||||||
|
val icon = Icon.createWithResource(context, android.R.drawable.ic_media_play)
|
||||||
whenever(mediaSmartspaceBaseAction.extras).thenReturn(recommendationExtras)
|
whenever(mediaSmartspaceBaseAction.extras).thenReturn(recommendationExtras)
|
||||||
whenever(mediaSmartspaceTarget.baseAction).thenReturn(mediaSmartspaceBaseAction)
|
whenever(mediaSmartspaceTarget.baseAction).thenReturn(mediaSmartspaceBaseAction)
|
||||||
whenever(mediaRecommendationItem.extras).thenReturn(recommendationExtras)
|
whenever(mediaRecommendationItem.extras).thenReturn(recommendationExtras)
|
||||||
|
whenever(mediaRecommendationItem.icon).thenReturn(icon)
|
||||||
|
validRecommendationList = listOf(
|
||||||
|
mediaRecommendationItem, mediaRecommendationItem, mediaRecommendationItem
|
||||||
|
)
|
||||||
whenever(mediaSmartspaceTarget.smartspaceTargetId).thenReturn(KEY_MEDIA_SMARTSPACE)
|
whenever(mediaSmartspaceTarget.smartspaceTargetId).thenReturn(KEY_MEDIA_SMARTSPACE)
|
||||||
whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
|
whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
|
||||||
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf(mediaRecommendationItem))
|
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(validRecommendationList)
|
||||||
whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L)
|
whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L)
|
||||||
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(false)
|
whenever(mediaFlags.areMediaSessionActionsEnabled(any(), any())).thenReturn(false)
|
||||||
whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
|
whenever(logger.getNewInstanceId()).thenReturn(instanceIdSequence.newInstanceId())
|
||||||
@@ -507,10 +514,9 @@ class MediaDataManagerTest : SysuiTestCase() {
|
|||||||
eq(SmartspaceMediaData(
|
eq(SmartspaceMediaData(
|
||||||
targetId = KEY_MEDIA_SMARTSPACE,
|
targetId = KEY_MEDIA_SMARTSPACE,
|
||||||
isActive = true,
|
isActive = true,
|
||||||
isValid = true,
|
|
||||||
packageName = PACKAGE_NAME,
|
packageName = PACKAGE_NAME,
|
||||||
cardAction = mediaSmartspaceBaseAction,
|
cardAction = mediaSmartspaceBaseAction,
|
||||||
recommendations = listOf(mediaRecommendationItem),
|
recommendations = validRecommendationList,
|
||||||
dismissIntent = DISMISS_INTENT,
|
dismissIntent = DISMISS_INTENT,
|
||||||
headphoneConnectionTimeMillis = 1234L,
|
headphoneConnectionTimeMillis = 1234L,
|
||||||
instanceId = InstanceId.fakeInstanceId(instanceId))),
|
instanceId = InstanceId.fakeInstanceId(instanceId))),
|
||||||
@@ -529,7 +535,6 @@ class MediaDataManagerTest : SysuiTestCase() {
|
|||||||
eq(EMPTY_SMARTSPACE_MEDIA_DATA.copy(
|
eq(EMPTY_SMARTSPACE_MEDIA_DATA.copy(
|
||||||
targetId = KEY_MEDIA_SMARTSPACE,
|
targetId = KEY_MEDIA_SMARTSPACE,
|
||||||
isActive = true,
|
isActive = true,
|
||||||
isValid = false,
|
|
||||||
dismissIntent = DISMISS_INTENT,
|
dismissIntent = DISMISS_INTENT,
|
||||||
headphoneConnectionTimeMillis = 1234L,
|
headphoneConnectionTimeMillis = 1234L,
|
||||||
instanceId = InstanceId.fakeInstanceId(instanceId))),
|
instanceId = InstanceId.fakeInstanceId(instanceId))),
|
||||||
@@ -555,7 +560,6 @@ class MediaDataManagerTest : SysuiTestCase() {
|
|||||||
eq(EMPTY_SMARTSPACE_MEDIA_DATA.copy(
|
eq(EMPTY_SMARTSPACE_MEDIA_DATA.copy(
|
||||||
targetId = KEY_MEDIA_SMARTSPACE,
|
targetId = KEY_MEDIA_SMARTSPACE,
|
||||||
isActive = true,
|
isActive = true,
|
||||||
isValid = false,
|
|
||||||
dismissIntent = null,
|
dismissIntent = null,
|
||||||
headphoneConnectionTimeMillis = 1234L,
|
headphoneConnectionTimeMillis = 1234L,
|
||||||
instanceId = InstanceId.fakeInstanceId(instanceId))),
|
instanceId = InstanceId.fakeInstanceId(instanceId))),
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package com.android.systemui.media
|
||||||
|
|
||||||
|
import android.app.smartspace.SmartspaceAction
|
||||||
|
import android.graphics.drawable.Icon
|
||||||
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.internal.logging.InstanceId
|
||||||
|
import com.android.systemui.R
|
||||||
|
import com.android.systemui.SysuiTestCase
|
||||||
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
class SmartspaceMediaDataTest : SysuiTestCase() {
|
||||||
|
|
||||||
|
private val icon: Icon = Icon.createWithResource(context, R.drawable.ic_media_play)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getValidRecommendations_onlyReturnsRecsWithIcons() {
|
||||||
|
val withIcon1 = SmartspaceAction.Builder("id", "title").setIcon(icon).build()
|
||||||
|
val withIcon2 = SmartspaceAction.Builder("id", "title").setIcon(icon).build()
|
||||||
|
val withoutIcon1 = SmartspaceAction.Builder("id", "title").setIcon(null).build()
|
||||||
|
val withoutIcon2 = SmartspaceAction.Builder("id", "title").setIcon(null).build()
|
||||||
|
val recommendations = listOf(withIcon1, withoutIcon1, withIcon2, withoutIcon2)
|
||||||
|
|
||||||
|
val data = DEFAULT_DATA.copy(recommendations = recommendations)
|
||||||
|
|
||||||
|
assertThat(data.getValidRecommendations()).isEqualTo(listOf(withIcon1, withIcon2))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isValid_emptyList_returnsFalse() {
|
||||||
|
val data = DEFAULT_DATA.copy(recommendations = listOf())
|
||||||
|
|
||||||
|
assertThat(data.isValid()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isValid_tooFewRecs_returnsFalse() {
|
||||||
|
val data = DEFAULT_DATA.copy(
|
||||||
|
recommendations = listOf(
|
||||||
|
SmartspaceAction.Builder("id", "title").setIcon(icon).build()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertThat(data.isValid()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isValid_tooFewRecsWithIcons_returnsFalse() {
|
||||||
|
val recommendations = mutableListOf<SmartspaceAction>()
|
||||||
|
// Add one fewer recommendation w/ icon than the number required
|
||||||
|
for (i in 1 until NUM_REQUIRED_RECOMMENDATIONS) {
|
||||||
|
recommendations.add(
|
||||||
|
SmartspaceAction.Builder("id", "title").setIcon(icon).build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
for (i in 1 until 3) {
|
||||||
|
recommendations.add(
|
||||||
|
SmartspaceAction.Builder("id", "title").setIcon(null).build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val data = DEFAULT_DATA.copy(recommendations = recommendations)
|
||||||
|
|
||||||
|
assertThat(data.isValid()).isFalse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isValid_enoughRecsWithIcons_returnsTrue() {
|
||||||
|
val recommendations = mutableListOf<SmartspaceAction>()
|
||||||
|
// Add the number of required recommendations
|
||||||
|
for (i in 0 until NUM_REQUIRED_RECOMMENDATIONS) {
|
||||||
|
recommendations.add(
|
||||||
|
SmartspaceAction.Builder("id", "title").setIcon(icon).build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val data = DEFAULT_DATA.copy(recommendations = recommendations)
|
||||||
|
|
||||||
|
assertThat(data.isValid()).isTrue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isValid_manyRecsWithIcons_returnsTrue() {
|
||||||
|
val recommendations = mutableListOf<SmartspaceAction>()
|
||||||
|
// Add more than enough recommendations
|
||||||
|
for (i in 0 until NUM_REQUIRED_RECOMMENDATIONS + 3) {
|
||||||
|
recommendations.add(
|
||||||
|
SmartspaceAction.Builder("id", "title").setIcon(icon).build()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val data = DEFAULT_DATA.copy(recommendations = recommendations)
|
||||||
|
|
||||||
|
assertThat(data.isValid()).isTrue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val DEFAULT_DATA = SmartspaceMediaData(
|
||||||
|
targetId = "INVALID",
|
||||||
|
isActive = false,
|
||||||
|
packageName = "INVALID",
|
||||||
|
cardAction = null,
|
||||||
|
recommendations = emptyList(),
|
||||||
|
dismissIntent = null,
|
||||||
|
headphoneConnectionTimeMillis = 0,
|
||||||
|
instanceId = InstanceId.fakeInstanceId(-1)
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user