diff options
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt | 103 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java | 57 |
2 files changed, 122 insertions, 38 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index 2facf3dedd18..db5dbb0263c8 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -212,14 +212,32 @@ class MediaCarouselController @Inject constructor( isSsReactivated: Boolean ) { if (addOrUpdatePlayer(key, oldKey, data)) { + // Log card received if a new resumable media card is added MediaPlayerData.getMediaPlayer(key)?.let { logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED it.mInstanceId, + it.mUid, /* isRecommendationCard */ false, it.surfaceForSmartspaceLogging, rank = MediaPlayerData.getMediaPlayerIndex(key)) } } + if (isSsReactivated) { + // If resumable media is reactivated by headphone connection, update instance + // id for each card and log a receive event. + MediaPlayerData.players().forEachIndexed { index, it -> + if (it.recommendationViewHolder == null) { + it.mInstanceId = SmallHash.hash(it.mUid + + systemClock.currentTimeMillis().toInt()) + logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED + it.mInstanceId, + it.mUid, + /* isRecommendationCard */ false, + it.surfaceForSmartspaceLogging, + rank = index) + } + } + } if (mediaCarouselScrollHandler.visibleToUser && isSsReactivated && !mediaCarouselScrollHandler.qsExpanded) { // It could happen that reactived media player isn't visible to user because @@ -252,6 +270,7 @@ class MediaCarouselController @Inject constructor( MediaPlayerData.getMediaPlayer(key)?.let { logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED it.mInstanceId, + it.mUid, /* isRecommendationCard */ true, it.surfaceForSmartspaceLogging, rank = MediaPlayerData.getMediaPlayerIndex(key)) @@ -261,6 +280,7 @@ class MediaCarouselController @Inject constructor( MediaPlayerData.getMediaPlayerIndex(key)) { logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN it.mInstanceId, + it.mUid, /* isRecommendationCard */ true, it.surfaceForSmartspaceLogging) } @@ -339,9 +359,9 @@ class MediaCarouselController @Inject constructor( if (activeMediaIndex != -1) { previousVisiblePlayerKey?.let { val previousVisibleIndex = MediaPlayerData.playerKeys() - .indexOfFirst { key -> it == key } + .indexOfFirst { key -> it == key } mediaCarouselScrollHandler - .scrollToPlayer(previousVisibleIndex, activeMediaIndex) + .scrollToPlayer(previousVisibleIndex, activeMediaIndex) } ?: { mediaCarouselScrollHandler.scrollToPlayer(destIndex = activeMediaIndex) } @@ -355,11 +375,11 @@ class MediaCarouselController @Inject constructor( MediaPlayerData.moveIfExists(oldKey, key) val existingPlayer = MediaPlayerData.getMediaPlayer(key) val curVisibleMediaKey = MediaPlayerData.playerKeys() - .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex) + .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex) if (existingPlayer == null) { var newPlayer = mediaControlPanelFactory.get() newPlayer.attachPlayer( - PlayerViewHolder.create(LayoutInflater.from(context), mediaContent)) + PlayerViewHolder.create(LayoutInflater.from(context), mediaContent)) newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) @@ -407,14 +427,14 @@ class MediaCarouselController @Inject constructor( var newRecs = mediaControlPanelFactory.get() newRecs.attachRecommendation( - RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent)) + RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent)) newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT) + ViewGroup.LayoutParams.WRAP_CONTENT) newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp) newRecs.bindRecommendation(data.copy(backgroundColor = bgColor)) val curVisibleMediaKey = MediaPlayerData.playerKeys() - .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex) + .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex) MediaPlayerData.addMediaRecommendation(key, data, newRecs, shouldPrioritize, systemClock) updatePlayerToState(newRecs, noAnimation = true) reorderAllPlayers(curVisibleMediaKey) @@ -462,7 +482,7 @@ class MediaCarouselController @Inject constructor( removePlayer(key, dismissMediaData = false, dismissRecommendation = false) smartspaceMediaData?.let { addSmartspaceMediaRecommendations( - it.targetId, it, MediaPlayerData.shouldPrioritizeSs) + it.targetId, it, MediaPlayerData.shouldPrioritizeSs) } } else { removePlayer(key, dismissMediaData = false, dismissRecommendation = false) @@ -585,7 +605,7 @@ class MediaCarouselController @Inject constructor( ?: endShowsActive if (currentlyShowingOnlyActive != endShowsActive || ((currentTransitionProgress != 1.0f && currentTransitionProgress != 0.0f) && - startShowsActive != endShowsActive)) { + startShowsActive != endShowsActive)) { // Whenever we're transitioning from between differing states or the endstate differs // we reset the translation currentlyShowingOnlyActive = endShowsActive @@ -696,23 +716,43 @@ class MediaCarouselController @Inject constructor( } logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN mediaControlPanel.mInstanceId, + mediaControlPanel.mUid, isRecommendationCard, mediaControlPanel.surfaceForSmartspaceLogging) } } @JvmOverloads + /** + * Log Smartspace events + * + * @param eventId UI event id (e.g. 800 for SMARTSPACE_CARD_SEEN) + * @param instanceId id to uniquely identify a card, e.g. each headphone generates a new + * instanceId + * @param uid uid for the application that media comes from + * @param isRecommendationCard whether the card is media recommendation + * @param surface which display surface the media card is on (e.g. lockscreen, shade) + * @param interactedSubcardRank the rank for interacted media item for recommendation card, -1 + * for tapping on card but not on any media item, 0 for first media item, 1 for second, etc. + * @param interactedSubcardCardinality how many media items were shown to the user when there + * is user interaction + * @param rank the rank for media card in the media carousel, starting from 0 + * + */ fun logSmartspaceCardReported( eventId: Int, instanceId: Int, + uid: Int, isRecommendationCard: Boolean, surface: Int, + interactedSubcardRank: Int = 0, + interactedSubcardCardinality: Int = 0, rank: Int = mediaCarouselScrollHandler.visibleMediaIndex ) { // Only log media resume card when Smartspace data is available if (!isRecommendationCard && - !mediaManager.smartspaceMediaData.isActive && - MediaPlayerData.smartspaceMediaData == null) { + !mediaManager.smartspaceMediaData.isActive && + MediaPlayerData.smartspaceMediaData == null) { return } @@ -720,13 +760,20 @@ class MediaCarouselController @Inject constructor( SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED, eventId, instanceId, - if (isRecommendationCard) - SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__HEADPHONE_MEDIA_RECOMMENDATIONS - else - SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__HEADPHONE_RESUME_MEDIA, + // Deprecated, replaced with AiAi feature type so we don't need to create logging + // card type for each new feature. + SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD, surface, rank, - mediaContent.getChildCount()) + mediaContent.getChildCount(), + if (isRecommendationCard) + 15 // MEDIA_RECOMMENDATION + else + 31, // MEDIA_RESUME + uid, + interactedSubcardRank, + interactedSubcardCardinality + ) /* ktlint-disable max-line-length */ } @@ -738,18 +785,20 @@ class MediaCarouselController @Inject constructor( if (!recommendation.isEmpty()) { logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS recommendation.get(0).mInstanceId, + recommendation.get(0).mUid, true, recommendation.get(0).surfaceForSmartspaceLogging, - /* rank */-1) + rank = -1) } else { val visibleMediaIndex = mediaCarouselScrollHandler.visibleMediaIndex if (MediaPlayerData.players().size > visibleMediaIndex) { val player = MediaPlayerData.players().elementAt(visibleMediaIndex) logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS player.mInstanceId, - false, + player.mUid, + false, player.surfaceForSmartspaceLogging, - /* rank */-1) + rank = -1) } } mediaManager.onSwipeToDismiss() @@ -768,7 +817,7 @@ class MediaCarouselController @Inject constructor( @VisibleForTesting internal object MediaPlayerData { private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null, - emptyList(), emptyList(), "INVALID", null, null, null, true, null) + emptyList(), emptyList(), "INVALID", null, null, null, true, null) // Whether should prioritize Smartspace card. internal var shouldPrioritizeSs: Boolean = false private set @@ -776,18 +825,18 @@ internal object MediaPlayerData { private set data class MediaSortKey( - // Whether the item represents a Smartspace media recommendation. + // Whether the item represents a Smartspace media recommendation. val isSsMediaRec: Boolean, val data: MediaData, val updateTime: Long = 0 ) private val comparator = - compareByDescending<MediaSortKey> { it.data.isPlaying } - .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec } - .thenByDescending { it.data.isLocalSession } - .thenByDescending { !it.data.resumption } - .thenByDescending { it.updateTime } + compareByDescending<MediaSortKey> { it.data.isPlaying } + .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec } + .thenByDescending { it.data.isLocalSession } + .thenByDescending { !it.data.resumption } + .thenByDescending { it.updateTime } private val mediaPlayers = TreeMap<MediaSortKey, MediaControlPanel>(comparator) private val mediaData: MutableMap<String, MediaSortKey> = mutableMapOf() @@ -888,4 +937,4 @@ internal object MediaPlayerData { } return false } -} +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 15a70831b2f9..afe9e5a6ee95 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -33,6 +33,7 @@ import android.graphics.drawable.Icon; import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.PlaybackState; +import android.os.Process; import android.text.Layout; import android.util.Log; import android.view.View; @@ -111,6 +112,9 @@ public class MediaControlPanel { private int mAlbumArtSize; // Instance id for logging purpose. protected int mInstanceId = -1; + // Uid for the media app. + protected int mUid = Process.INVALID_UID; + private int mSmartspaceMediaItemsCount; private MediaCarouselController mMediaCarouselController; private final MediaOutputDialogFactory mMediaOutputDialogFactory; @@ -266,7 +270,13 @@ public class MediaControlPanel { } mKey = key; MediaSession.Token token = data.getToken(); - mInstanceId = SmallHash.hash(data.getPackageName()); + PackageManager packageManager = mContext.getPackageManager(); + try { + mUid = packageManager.getApplicationInfo(data.getPackageName(), 0 /* flags */).uid; + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "Unable to look up package name", e); + } + mInstanceId = SmallHash.hash(mUid); mBackgroundColor = data.getBackgroundColor(); if (mToken == null || !mToken.equals(token)) { @@ -531,10 +541,11 @@ public class MediaControlPanel { } // Set up recommendation card's header. - ApplicationInfo applicationInfo = null; + ApplicationInfo applicationInfo; try { applicationInfo = mContext.getPackageManager() .getApplicationInfo(data.getPackageName(), 0 /* flags */); + mUid = applicationInfo.uid; } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Fail to get media recommendation's app info", e); return; @@ -553,7 +564,8 @@ public class MediaControlPanel { headerTitleText.setText(appLabel); } // Set up media rec card's tap action if applicable. - setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction()); + setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(), + /* interactedSubcardRank */ -1); // Set up media rec card's accessibility label. recommendationCard.setContentDescription( mContext.getString(R.string.controls_media_smartspace_rec_description, appLabel)); @@ -567,7 +579,8 @@ public class MediaControlPanel { ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout(); int mediaRecommendationNum = Math.min(mediaRecommendationList.size(), MEDIA_RECOMMENDATION_MAX_NUM); - for (int itemIndex = 0, uiComponentIndex = 0; + int uiComponentIndex = 0; + for (int itemIndex = 0; itemIndex < mediaRecommendationNum && uiComponentIndex < mediaRecommendationNum; itemIndex++) { SmartspaceAction recommendation = mediaRecommendationList.get(itemIndex); @@ -582,7 +595,8 @@ public class MediaControlPanel { // Set up the media item's click listener if applicable. ViewGroup mediaCoverContainer = mediaCoverContainers.get(uiComponentIndex); - setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation); + setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation, + uiComponentIndex); // Set up the accessibility label for the media item. String artistName = recommendation.getExtras() @@ -614,10 +628,10 @@ public class MediaControlPanel { mediaCoverItemsResIds.get(uiComponentIndex), true); setVisibleAndAlpha(expandedSet, mediaCoverContainersResIds.get(uiComponentIndex), true); - uiComponentIndex++; } + mSmartspaceMediaItemsCount = uiComponentIndex; // Set up long press to show guts setting panel. mRecommendationViewHolder.getDismiss().setOnClickListener(v -> { logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS @@ -750,7 +764,8 @@ public class MediaControlPanel { private void setSmartspaceRecItemOnClickListener( @NonNull View view, - @NonNull SmartspaceAction action) { + @NonNull SmartspaceAction action, + int interactedSubcardRank) { if (view == null || action == null || action.getIntent() == null || action.getIntent().getExtras() == null) { Log.e(TAG, "No tap action can be set up"); @@ -758,9 +773,10 @@ public class MediaControlPanel { } view.setOnClickListener(v -> { - // When media recommendation card is shown, it will always be the top card. logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK - /* isRecommendationCard */ true); + /* isRecommendationCard */ true, + interactedSubcardRank, + getSmartspaceSubCardCardinality()); if (shouldSmartspaceRecItemOpenInForeground(action)) { // Request to unlock the device if the activity needs to be opened in foreground. @@ -818,9 +834,28 @@ public class MediaControlPanel { } private void logSmartspaceCardReported(int eventId, boolean isRecommendationCard) { + logSmartspaceCardReported(eventId, isRecommendationCard, + /* interactedSubcardRank */ 0, + /* interactedSubcardCardinality */ 0); + } + + private void logSmartspaceCardReported(int eventId, boolean isRecommendationCard, + int interactedSubcardRank, int interactedSubcardCardinality) { mMediaCarouselController.logSmartspaceCardReported(eventId, mInstanceId, + mUid, isRecommendationCard, - getSurfaceForSmartspaceLogging()); + getSurfaceForSmartspaceLogging(), + interactedSubcardRank, + interactedSubcardCardinality); + } + + private int getSmartspaceSubCardCardinality() { + if (!mMediaCarouselController.getMediaCarouselScrollHandler().getQsExpanded() + && mSmartspaceMediaItemsCount > 3) { + return 3; + } + + return mSmartspaceMediaItemsCount; } -} +}
\ No newline at end of file |