diff options
author | Arnaud Berry <arnaudberry@google.com> | 2023-12-20 15:53:13 -0800 |
---|---|---|
committer | Arnaud Berry <arnaudberry@google.com> | 2023-12-21 12:54:25 -0800 |
commit | 595d15cd3506f6bb82d960f6878c665fba428ff1 (patch) | |
tree | 575c1688a4632d3b46fc33752e875908804936b9 | |
parent | 28ef1a8a4ad976fd044a6b5c089d5104c93ff75b (diff) | |
download | Media-595d15cd3506f6bb82d960f6878c665fba428ff1.tar.gz |
Improve anaylitics for the playback queue
Fixes: 317269148
Fixes: 317277338
Test: manual with TestMediaApp and gradle
Change-Id: Ia7ebd7c8e5735f1c9bac73a492bfa1941fee00cb
-rw-r--r-- | src/com/android/car/media/AnalyticsHelper.java | 19 | ||||
-rw-r--r-- | src/com/android/car/media/BrowseViewController.java | 13 | ||||
-rw-r--r-- | src/com/android/car/media/MediaActivity.java | 6 | ||||
-rw-r--r-- | src/com/android/car/media/MediaActivityController.java | 15 | ||||
-rw-r--r-- | src/com/android/car/media/NowPlayingController.java | 9 | ||||
-rw-r--r-- | src/com/android/car/media/PlaybackQueueController.java | 61 |
6 files changed, 84 insertions, 39 deletions
diff --git a/src/com/android/car/media/AnalyticsHelper.java b/src/com/android/car/media/AnalyticsHelper.java index bb94fa9..4d0b86a 100644 --- a/src/com/android/car/media/AnalyticsHelper.java +++ b/src/com/android/car/media/AnalyticsHelper.java @@ -19,7 +19,7 @@ package com.android.car.media; import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_ACTION_HIDE; import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_ACTION_MODE_NONE; import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_ACTION_MODE_SCROLL; -import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_COMPONENT_BROWSE_LIST; +import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_ACTION_SHOW; import static androidx.recyclerview.widget.RecyclerView.NO_POSITION; import androidx.annotation.OptIn; @@ -42,20 +42,20 @@ public class AnalyticsHelper { * @return the currently visible items. */ public static List<String> sendVisibleItemsInc( + @AnalyticsEvent.ViewComponent int viewComp, MediaItemsRepository repo, MediaItemMetadata parentItem, List<String> prevItems, List<MediaItemMetadata> items, int currFirst, int currLast, boolean fromScroll) { - //Handle empty list by hiding previous and returning empty. + // Handle empty list by hiding previous and returning empty. if (items.isEmpty() && !prevItems.isEmpty()) { repo.getAnalyticsManager().sendVisibleItemsEvents( - parentItem != null ? parentItem.getId() : null, - VIEW_COMPONENT_BROWSE_LIST, VIEW_ACTION_HIDE, + parentItem != null ? parentItem.getId() : null, viewComp, VIEW_ACTION_HIDE, fromScroll ? VIEW_ACTION_MODE_SCROLL : VIEW_ACTION_MODE_NONE, new ArrayList<>(prevItems)); return List.of(); } - //If for any reason there are no visible items or error state + // If for any reason there are no visible items or error state // we have nothing to show, hide prev if (currFirst == NO_POSITION || currLast == NO_POSITION @@ -64,8 +64,7 @@ public class AnalyticsHelper { if (!prevItems.isEmpty()) { repo.getAnalyticsManager().sendVisibleItemsEvents( - parentItem != null ? parentItem.getId() : null, - VIEW_COMPONENT_BROWSE_LIST, VIEW_ACTION_HIDE, + parentItem != null ? parentItem.getId() : null, viewComp, VIEW_ACTION_HIDE, fromScroll ? VIEW_ACTION_MODE_SCROLL : VIEW_ACTION_MODE_NONE, new ArrayList<>(prevItems)); } @@ -91,15 +90,13 @@ public class AnalyticsHelper { if (!delta.isEmpty()) { repo.getAnalyticsManager().sendVisibleItemsEvents( - parentItem != null ? parentItem.getId() : null, - VIEW_COMPONENT_BROWSE_LIST, VIEW_ACTION_HIDE, + parentItem != null ? parentItem.getId() : null, viewComp, VIEW_ACTION_HIDE, fromScroll ? VIEW_ACTION_MODE_SCROLL : VIEW_ACTION_MODE_NONE, new ArrayList<>(delta)); } if (!deltaNew.isEmpty()) { repo.getAnalyticsManager().sendVisibleItemsEvents( - parentItem != null ? parentItem.getId() : null, - VIEW_COMPONENT_BROWSE_LIST, AnalyticsEvent.VIEW_ACTION_SHOW, + parentItem != null ? parentItem.getId() : null, viewComp, VIEW_ACTION_SHOW, fromScroll ? VIEW_ACTION_MODE_SCROLL : VIEW_ACTION_MODE_NONE, new ArrayList<>(deltaNew)); } diff --git a/src/com/android/car/media/BrowseViewController.java b/src/com/android/car/media/BrowseViewController.java index 9215576..75bf306 100644 --- a/src/com/android/car/media/BrowseViewController.java +++ b/src/com/android/car/media/BrowseViewController.java @@ -21,6 +21,7 @@ import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_PLAYBACK; import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_ACTION_HIDE; import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_ACTION_SHOW; +import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_COMPONENT_BROWSE_LIST; import static androidx.recyclerview.widget.RecyclerView.NO_POSITION; import static com.android.car.apps.common.util.ViewUtils.removeFromParent; @@ -164,7 +165,7 @@ public class BrowseViewController { protected void onPlayableItemClicked(@NonNull MediaItemMetadata item) { if (item.getId() != null) { mMediaRepo.getAnalyticsManager().sendMediaClickedEvent(item.getId(), - AnalyticsEvent.VIEW_COMPONENT_BROWSE_LIST); + VIEW_COMPONENT_BROWSE_LIST); } mCallbacks.onPlayableItemClicked(item); } @@ -173,7 +174,7 @@ public class BrowseViewController { protected void onBrowsableItemClicked(@NonNull MediaItemMetadata item) { if (item.getId() != null) { mMediaRepo.getAnalyticsManager().sendMediaClickedEvent(item.getId(), - AnalyticsEvent.VIEW_COMPONENT_BROWSE_LIST); + VIEW_COMPONENT_BROWSE_LIST); } mCallbacks.goToMediaItem(item); } @@ -218,7 +219,7 @@ public class BrowseViewController { .collect(Collectors.toCollection(ArrayList::new)); mMediaRepo.getAnalyticsManager().sendVisibleItemsEvents( - parentId, AnalyticsEvent.VIEW_COMPONENT_BROWSE_LIST, + parentId, VIEW_COMPONENT_BROWSE_LIST, isShown ? AnalyticsEvent.VIEW_ACTION_SHOW : AnalyticsEvent.VIEW_ACTION_HIDE, AnalyticsEvent.VIEW_ACTION_MODE_NONE, itemsSublist); } @@ -546,9 +547,9 @@ public class BrowseViewController { && mMediaItems.getValue().getData() != null) { int currFirst = mLimitedBrowseAdapter.findFirstVisibleItemIndex(); int currLast = mLimitedBrowseAdapter.findLastVisibleItemIndex(true); - mPrevVisible = AnalyticsHelper.sendVisibleItemsInc(mMediaRepo, mParentItem, - mPrevVisible, mMediaItems.getValue().getData(), currFirst, currLast, - fromScroll); + mPrevVisible = AnalyticsHelper.sendVisibleItemsInc(VIEW_COMPONENT_BROWSE_LIST, + mMediaRepo, mParentItem, mPrevVisible, mMediaItems.getValue().getData(), + currFirst, currLast, fromScroll); } } diff --git a/src/com/android/car/media/MediaActivity.java b/src/com/android/car/media/MediaActivity.java index 7e71326..3ef4d4b 100644 --- a/src/com/android/car/media/MediaActivity.java +++ b/src/com/android/car/media/MediaActivity.java @@ -610,6 +610,7 @@ public class MediaActivity extends FragmentActivity implements MediaActivityCont VIEW_COMPONENT_BROWSE_LIST, VIEW_ACTION_HIDE); break; case PLAYBACK: + mMediaActivityController.onNpvActualVisibilityChanged(false); getMediaItemsRepository().getAnalyticsManager().sendViewChangedEvent( VIEW_COMPONENT_PLAYBACK, VIEW_ACTION_HIDE); break; @@ -632,7 +633,10 @@ public class MediaActivity extends FragmentActivity implements MediaActivityCont mPlaybackContainer.setY(0); mPlaybackContainer.setAlpha(0f); ViewUtils.hideViewAnimated(mErrorContainer, fadeOutDuration); - ViewUtils.showViewAnimated(mPlaybackContainer, mFadeDuration); + // Reporting the view as visible at the end of the animation gives a chance for the + // new queue to be loaded and avoids reporting the old queue as visible. + ViewUtils.showViewAnimated(mPlaybackContainer, mFadeDuration, + view -> mMediaActivityController.onNpvActualVisibilityChanged(true)); ViewUtils.hideViewAnimated(mBrowseContainer, fadeOutDuration); getMediaItemsRepository().getAnalyticsManager().sendViewChangedEvent( VIEW_COMPONENT_PLAYBACK, VIEW_ACTION_SHOW); diff --git a/src/com/android/car/media/MediaActivityController.java b/src/com/android/car/media/MediaActivityController.java index a1442f0..827118a 100644 --- a/src/com/android/car/media/MediaActivityController.java +++ b/src/com/android/car/media/MediaActivityController.java @@ -20,6 +20,7 @@ import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_BROWSE; import static android.car.media.CarMediaManager.MEDIA_SOURCE_MODE_PLAYBACK; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS; +import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_COMPONENT_BROWSE_LIST; import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_COMPONENT_BROWSE_TABS; import static com.android.car.apps.common.util.ViewUtils.showHideViewAnimated; @@ -168,9 +169,9 @@ public class MediaActivityController extends ViewControllerBase { (LimitedBrowseAdapter) toolbarSearchResultsView.getAdapter(); int currFirst = limitedBrowseAdapter.findFirstVisibleItemIndex(); int currLast = limitedBrowseAdapter.findLastVisibleItemIndex(canKeyboardCover); - mPrevVisible = AnalyticsHelper.sendVisibleItemsInc(mediaItemsRepository, null, - mPrevVisible, limitedBrowseAdapter.getItems(), currFirst, currLast, - fromScroll); + mPrevVisible = AnalyticsHelper.sendVisibleItemsInc(VIEW_COMPONENT_BROWSE_LIST, + mediaItemsRepository, null, mPrevVisible, limitedBrowseAdapter.getItems(), + currFirst, currLast, fromScroll); } }; } @@ -353,6 +354,14 @@ public class MediaActivityController extends ViewControllerBase { mNowPlayingController.setListener(mNowPlayingListener); } + /** + * Tells the Now Playing View controller what is actually happening to its view, so that it + * can be considered hidden right when a hiding animation starts. + */ + public void onNpvActualVisibilityChanged(boolean isShown) { + mNowPlayingController.onActualVisibilityChanged(isShown); + } + private BrowseViewController recreateController(BrowseStack.BrowseEntry entry) { switch (entry.mType) { case TREE_ROOT: diff --git a/src/com/android/car/media/NowPlayingController.java b/src/com/android/car/media/NowPlayingController.java index eccaf2e..66eb7cf 100644 --- a/src/com/android/car/media/NowPlayingController.java +++ b/src/com/android/car/media/NowPlayingController.java @@ -245,6 +245,14 @@ public class NowPlayingController { }); } + /** + * Tells the controller what is actually happening to its view, so that it can be + * considered hidden right when a hiding animation starts. + */ + public void onActualVisibilityChanged(boolean isShown) { + mPlaybackQueueController.onActualVisibilityChanged(isShown && mQueueIsVisible); + } + private void initPlaybackControls(PlaybackControlsActionBar playbackControls) { mPlaybackControls = playbackControls; mPlaybackControls.setModel(mPlaybackViewModel, getActivity()); @@ -358,6 +366,7 @@ public class NowPlayingController { if (mQueueIsVisible != visible) { mQueueIsVisible = visible; + mPlaybackQueueController.onActualVisibilityChanged(mQueueIsVisible); if (mQueueIsVisible) { ViewUtils.showViewsAnimated(mViewsToShowWhenQueueIsVisible, mFadeDuration); ViewUtils.hideViewsAnimated(mViewsToHideWhenQueueIsVisible, mFadeDuration); diff --git a/src/com/android/car/media/PlaybackQueueController.java b/src/com/android/car/media/PlaybackQueueController.java index defc404..538c44e 100644 --- a/src/com/android/car/media/PlaybackQueueController.java +++ b/src/com/android/car/media/PlaybackQueueController.java @@ -16,6 +16,9 @@ package com.android.car.media; +import static androidx.car.app.mediaextensions.analytics.event.AnalyticsEvent.VIEW_COMPONENT_QUEUE_LIST; +import static androidx.recyclerview.widget.RecyclerView.NO_POSITION; + import static com.android.car.ui.recyclerview.RangeFilter.INVALID_INDEX; import android.content.Context; @@ -66,22 +69,24 @@ public class PlaybackQueueController { private static final String TAG = "PlaybackQueueController"; - private Callbacks mCallbacks; - private LifeCycleObserverUxrContentLimiter mUxrContentLimiter; - private PlaybackViewModel mPlaybackViewModel; - private MediaItemsRepository mMediaItemsRepository; + private final Callbacks mCallbacks; + private final LifeCycleObserverUxrContentLimiter mUxrContentLimiter; + private final PlaybackViewModel mPlaybackViewModel; + private final MediaItemsRepository mMediaItemsRepository; private QueueItemsAdapter mQueueAdapter; - private CarUiRecyclerView mQueue; + private boolean mIsActuallyVisible = false; + private List<String> mPrevVisibleItems = new ArrayList<>(); + private final CarUiRecyclerView mQueue; private PlaybackQueueCallback mPlaybackQueueCallback; private DefaultItemAnimator mItemAnimator; private PlaybackViewModel.PlaybackController mController; private Long mActiveQueueItemId; - private boolean mShowTimeForActiveQueueItem; - private boolean mShowIconForActiveQueueItem; - private boolean mShowThumbnailForQueueItem; - private boolean mShowSubtitleForQueueItem; + private final boolean mShowTimeForActiveQueueItem; + private final boolean mShowIconForActiveQueueItem; + private final boolean mShowThumbnailForQueueItem; + private final boolean mShowSubtitleForQueueItem; /** * The callbacks used to communicate the user interactions to the queue fragment listeners. @@ -510,6 +515,31 @@ public class PlaybackQueueController { mPlaybackQueueCallback = callback; } + /** + * Tells the controller what is actually happening to its view, so that it can be + * considered hidden right when a hiding animation starts. + */ + public void onActualVisibilityChanged(boolean isVisible) { + if (mIsActuallyVisible != isVisible) { + mIsActuallyVisible = isVisible; + sendVisibleItemsIncremental(isVisible, false); + } + } + + private void sendVisibleItemsIncremental(boolean isShown, boolean fromScroll) { + if (isShown) { + int currFirst = mQueueAdapter.findFirstVisibleItemIndex(); + int currLast = mQueueAdapter.findLastVisibleItemIndex(); + mPrevVisibleItems = AnalyticsHelper.sendVisibleItemsInc(VIEW_COMPONENT_QUEUE_LIST, + mMediaItemsRepository, null, mPrevVisibleItems, mQueueAdapter.mQueueItems, + currFirst, currLast, fromScroll); + } else { + mPrevVisibleItems = AnalyticsHelper.sendVisibleItemsInc(VIEW_COMPONENT_QUEUE_LIST, + mMediaItemsRepository, null, mPrevVisibleItems, mQueueAdapter.mQueueItems, + NO_POSITION, NO_POSITION, false); + } + } + private void initQueue() { int decorationHeight = getActivity().getResources().getDimensionPixelSize( @@ -534,24 +564,16 @@ public class PlaybackQueueController { }); mQueue.setAdapter(mQueueAdapter); mQueue.addOnScrollListener(new CarUiRecyclerView.OnScrollListener() { - List<String> mPrevVisible = new ArrayList<>(); @Override public void onScrolled(CarUiRecyclerView recyclerView, int dx, int dy) { //dx and dy are 0 when items in RV change or layout is requested. We should // use this to trigger querying what is visible. - sendScrollEvent(dx != 0 || dy != 0); + sendVisibleItemsIncremental(true, (dx != 0 || dy != 0)); } @Override public void onScrollStateChanged(CarUiRecyclerView recyclerView, int newState) {} - - private void sendScrollEvent(boolean fromScroll) { - int currFirst = mQueueAdapter.findFirstVisibleItemIndex(); - int currLast = mQueueAdapter.findLastVisibleItemIndex(); - mPrevVisible = AnalyticsHelper.sendVisibleItemsInc(mMediaItemsRepository, null, - mPrevVisible, mQueueAdapter.mQueueItems, currFirst, currLast, fromScroll); - } }); // Disable item changed animation. mItemAnimator = new DefaultItemAnimator(); @@ -570,6 +592,9 @@ public class PlaybackQueueController { void setQueue(List<MediaItemMetadata> queueItems) { mQueueAdapter.setItems(queueItems); + if (mIsActuallyVisible) { + sendVisibleItemsIncremental(/* visible */ true, /* fromScroll */ false); + } } private void onQueueItemClicked(MediaItemMetadata item) { |