Populate additional fields for smartspace logging
1. Log package uid for media card 2. Log interacted subcard rank and cardinality for recommendation card 3. Log received event for reactived resume card 4. Log card type as int instead of enum Test: https://paste.googleplex.com/4557927936425984 Bug: 181364757,196637550 Change-Id: I2297a8febcaa8e49cf61f1727bd11ffcf0a13bdf
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user