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:
Jieru Shi
2021-08-16 20:11:37 -07:00
parent 2747904ead
commit c5daad2afb
2 changed files with 122 additions and 38 deletions

View File

@@ -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
}
}
}

View File

@@ -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;
}
}