diff options
| author | 2021-04-10 14:55:08 +0000 | |
|---|---|---|
| committer | 2021-04-10 14:55:08 +0000 | |
| commit | d8a78dcb51f7281bd89f222f8e84bb0e7d394b40 (patch) | |
| tree | bb67cd8615e914753a98404ecf6e1cf635a79d0a | |
| parent | 34440439c57a2ea0f751b9fe673a10ed3f7a971c (diff) | |
| parent | 629f3cb0bb6f587795a4d418ec17b9d1bb202a30 (diff) | |
Merge "Add Smartspace media card in media carousel when the Ss data is available." into sc-dev
12 files changed, 566 insertions, 88 deletions
diff --git a/packages/SystemUI/res/drawable/bg_smartspace_media_item.xml b/packages/SystemUI/res/drawable/bg_smartspace_media_item.xml new file mode 100644 index 000000000000..69390848245d --- /dev/null +++ b/packages/SystemUI/res/drawable/bg_smartspace_media_item.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> + <solid android:color="@android:color/white" /> + <corners android:radius="@dimen/qs_media_album_radius" /> +</shape>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/smartspace_card_media.xml b/packages/SystemUI/res/layout/smartspace_card_media.xml new file mode 100644 index 000000000000..a03044f014d4 --- /dev/null +++ b/packages/SystemUI/res/layout/smartspace_card_media.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<com.android.systemui.util.animation.TransitionLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/media_recommendations" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="8dp" + android:paddingBottom="8dp" + android:clipChildren="false" + android:clipToPadding="false" + android:forceHasOverlappingRendering="false" + android:background="@drawable/qs_media_background"> + + <ImageView + android:id="@+id/media_cover1" + android:layout_width="@dimen/qs_aa_media_rec_album_size" + android:layout_height="@dimen/qs_aa_media_rec_album_size" + android:adjustViewBounds="true" + android:background="@drawable/bg_smartspace_media_item" + android:clipToOutline="true" + android:scaleType="centerCrop"/> + + <ImageView + android:id="@+id/media_logo1" + android:layout_width="@dimen/qs_aa_media_rec_icon_size" + android:layout_height="@dimen/qs_aa_media_rec_icon_size" /> + + <ImageView + android:id="@+id/media_cover2" + android:layout_width="@dimen/qs_aa_media_rec_album_size" + android:layout_height="@dimen/qs_aa_media_rec_album_size" + android:adjustViewBounds="true" + android:background="@drawable/bg_smartspace_media_item" + android:clipToOutline="true" + android:scaleType="centerCrop"/> + + <ImageView + android:id="@+id/media_logo2" + android:layout_width="@dimen/qs_aa_media_rec_icon_size" + android:layout_height="@dimen/qs_aa_media_rec_icon_size" /> + + <ImageView + android:id="@+id/media_cover3" + android:layout_width="@dimen/qs_aa_media_rec_album_size" + android:layout_height="@dimen/qs_aa_media_rec_album_size" + android:adjustViewBounds="true" + android:background="@drawable/bg_smartspace_media_item" + android:clipToOutline="true" + android:scaleType="centerCrop"/> + + <ImageView + android:id="@+id/media_logo3" + android:layout_width="@dimen/qs_aa_media_rec_icon_size" + android:layout_height="@dimen/qs_aa_media_rec_icon_size" /> + + <ImageView + android:id="@+id/media_cover4" + android:layout_width="@dimen/qs_aa_media_rec_album_size" + android:layout_height="@dimen/qs_aa_media_rec_album_size" + android:adjustViewBounds="true" + android:background="@drawable/bg_smartspace_media_item" + android:clipToOutline="true" + android:scaleType="centerCrop"/> + + <ImageView + android:id="@+id/media_logo4" + android:layout_width="@dimen/qs_aa_media_rec_icon_size" + android:layout_height="@dimen/qs_aa_media_rec_icon_size" /> + +</com.android.systemui.util.animation.TransitionLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 3cd7a0b2da58..eb19b2eaba9a 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1232,6 +1232,7 @@ <dimen name="qs_media_padding">16dp</dimen> <dimen name="qs_media_panel_outer_padding">16dp</dimen> <dimen name="qs_media_album_size">120dp</dimen> + <dimen name="qs_media_album_radius">14dp</dimen> <dimen name="qs_media_icon_size">16dp</dimen> <dimen name="qs_center_guideline_padding">10dp</dimen> <dimen name="qs_seamless_icon_size">@dimen/qs_media_icon_size</dimen> @@ -1244,6 +1245,11 @@ <dimen name="qs_media_enabled_seekbar_vertical_padding">15dp</dimen> <dimen name="qs_media_disabled_seekbar_vertical_padding">16dp</dimen> + <!-- Size of Smartspace media recommendations cards in the QSPanel carousel --> + <dimen name="qs_aa_media_rec_album_size">80dp</dimen> + <dimen name="qs_aa_media_rec_icon_size">20dp</dimen> + + <!-- Window magnification --> <dimen name="magnification_border_drag_size">35dp</dimen> <dimen name="magnification_outer_border_margin">15dp</dimen> diff --git a/packages/SystemUI/res/xml/media_recommendation.xml b/packages/SystemUI/res/xml/media_recommendation.xml new file mode 100644 index 000000000000..a1bd231806a1 --- /dev/null +++ b/packages/SystemUI/res/xml/media_recommendation.xml @@ -0,0 +1,97 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<ConstraintSet + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <Constraint + android:id="@+id/media_cover1" + android:layout_width="@dimen/qs_aa_media_rec_album_size" + android:layout_height="@dimen/qs_aa_media_rec_album_size" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@id/media_cover2" + app:layout_constraintHorizontal_weight="1" + android:visibility="gone"/> + + <Constraint + android:id="@+id/media_logo1" + android:layout_width="@dimen/qs_aa_media_rec_icon_size" + android:layout_height="@dimen/qs_aa_media_rec_icon_size" + app:layout_constraintEnd_toEndOf="@+id/media_cover1" + app:layout_constraintBottom_toBottomOf="@+id/media_cover1" + android:visibility="gone" /> + + <Constraint + android:id="@+id/media_cover2" + android:layout_width="@dimen/qs_aa_media_rec_album_size" + android:layout_height="@dimen/qs_aa_media_rec_album_size" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/media_cover1" + app:layout_constraintEnd_toStartOf="@id/media_cover3" + app:layout_constraintHorizontal_weight="1" + android:visibility="gone"/> + + <Constraint + android:id="@+id/media_logo2" + android:layout_width="@dimen/qs_aa_media_rec_icon_size" + android:layout_height="@dimen/qs_aa_media_rec_icon_size" + app:layout_constraintEnd_toEndOf="@+id/media_cover2" + app:layout_constraintBottom_toBottomOf="@+id/media_cover2" + android:visibility="gone" /> + + <Constraint + android:id="@+id/media_cover3" + android:layout_width="@dimen/qs_aa_media_rec_album_size" + android:layout_height="@dimen/qs_aa_media_rec_album_size" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/media_cover2" + app:layout_constraintEnd_toStartOf="@id/media_cover4" + app:layout_constraintHorizontal_weight="1" + android:visibility="gone"/> + + <Constraint + android:id="@+id/media_logo3" + android:layout_width="@dimen/qs_aa_media_rec_icon_size" + android:layout_height="@dimen/qs_aa_media_rec_icon_size" + app:layout_constraintEnd_toEndOf="@+id/media_cover3" + app:layout_constraintBottom_toBottomOf="@+id/media_cover3" + android:visibility="gone" /> + + <Constraint + android:id="@+id/media_cover4" + android:layout_width="@dimen/qs_aa_media_rec_album_size" + android:layout_height="@dimen/qs_aa_media_rec_album_size" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintStart_toEndOf="@id/media_cover3" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_weight="1" + android:visibility="gone"/> + + <Constraint + android:id="@+id/media_logo4" + android:layout_width="@dimen/qs_aa_media_rec_icon_size" + android:layout_height="@dimen/qs_aa_media_rec_icon_size" + app:layout_constraintEnd_toEndOf="@+id/media_cover4" + app:layout_constraintBottom_toBottomOf="@+id/media_cover4" + android:visibility="gone" /> + +</ConstraintSet> diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt index 33681c8d03e5..2ecd40578d68 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt @@ -204,7 +204,7 @@ class MediaCarouselController @Inject constructor( override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) { Log.d(TAG, "My Smartspace media update is here") - addOrUpdateSmartspaceMediaRecommendations(key, data) + addSmartspaceMediaRecommendations(key, data) } override fun onMediaDataRemoved(key: String) { @@ -213,6 +213,7 @@ class MediaCarouselController @Inject constructor( override fun onSmartspaceMediaDataRemoved(key: String) { Log.d(TAG, "My Smartspace media removal request is received") + removePlayer(key) } }) mediaFrame.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> @@ -256,8 +257,10 @@ class MediaCarouselController @Inject constructor( private fun reorderAllPlayers() { mediaContent.removeAllViews() for (mediaPlayer in MediaPlayerData.players()) { - mediaPlayer.view?.let { + mediaPlayer.playerViewHolder?.let { mediaContent.addView(it.player) + } ?: mediaPlayer.recommendationViewHolder?.let { + mediaContent.addView(it.recommendations) } } mediaCarouselScrollHandler.onPlayersChanged() @@ -272,18 +275,19 @@ class MediaCarouselController @Inject constructor( val existingPlayer = MediaPlayerData.getMediaPlayer(key, oldKey) if (existingPlayer == null) { var newPlayer = mediaControlPanelFactory.get() - newPlayer.attach(PlayerViewHolder.create(LayoutInflater.from(context), mediaContent)) + newPlayer.attachPlayer( + PlayerViewHolder.create(LayoutInflater.from(context), mediaContent)) newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - newPlayer.view?.player?.setLayoutParams(lp) - newPlayer.bind(dataCopy, key) + newPlayer.playerViewHolder?.player?.setLayoutParams(lp) + newPlayer.bindPlayer(dataCopy, key) newPlayer.setListening(currentlyExpanded) MediaPlayerData.addMediaPlayer(key, dataCopy, newPlayer) updatePlayerToState(newPlayer, noAnimation = true) reorderAllPlayers() } else { - existingPlayer.bind(dataCopy, key) + existingPlayer.bindPlayer(dataCopy, key) MediaPlayerData.addMediaPlayer(key, dataCopy, existingPlayer) if (visualStabilityManager.isReorderingAllowed) { reorderAllPlayers() @@ -301,15 +305,43 @@ class MediaCarouselController @Inject constructor( } } - private fun addOrUpdateSmartspaceMediaRecommendations(key: String, data: SmartspaceTarget) { - // TODO(b/182813345): Add Smartspace media recommendation view. + private fun addSmartspaceMediaRecommendations(key: String, data: SmartspaceTarget) { + Log.d(TAG, "Updating smartspace target in carousel") + if (MediaPlayerData.getMediaPlayer(key, null) != null) { + Log.w(TAG, "Skip adding smartspace target in carousel") + return + } + + var newRecs = mediaControlPanelFactory.get() + newRecs.attachRecommendation( + RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent)) + newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions + val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT) + newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp) + newRecs.bindRecommendation(data, bgColor, { v -> removePlayer(key) }) + MediaPlayerData.addMediaPlayer(key, newRecs) + updatePlayerToState(newRecs, noAnimation = true) + reorderAllPlayers() + updatePageIndicator() + mediaCarousel.requiresRemeasuring = true + // Check postcondition: mediaContent should have the same number of children as there are + // elements in mediaPlayers. + if (MediaPlayerData.players().size != mediaContent.childCount) { + Log.wtf(TAG, "Size of players list and number of views in carousel are out of sync") + } } - private fun removePlayer(key: String, dismissMediaData: Boolean = true) { + private fun removePlayer( + key: String, + dismissMediaData: Boolean = true, + dismissRecommendation: Boolean = true + ) { val removed = MediaPlayerData.removeMediaPlayer(key) removed?.apply { mediaCarouselScrollHandler.onPrePlayerRemoved(removed) - mediaContent.removeView(removed.view?.player) + mediaContent.removeView(removed.playerViewHolder?.player) + mediaContent.removeView(removed.recommendationViewHolder?.recommendations) removed.onDestroy() mediaCarouselScrollHandler.onPlayersChanged() updatePageIndicator() @@ -318,6 +350,10 @@ class MediaCarouselController @Inject constructor( // Inform the media manager of a potentially late dismissal mediaManager.dismissMediaData(key, 0L) } + if (dismissRecommendation) { + // Inform the media manager of a potentially late dismissal + mediaManager.dismissSmartspaceRecommendation() + } } } @@ -539,23 +575,37 @@ 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) + private data class MediaSortKey( + // Is Smartspace media recommendation. When the Smartspace media is present, it should + // always be the first card in carousel. + val isSsMediaRec: Boolean, val data: MediaData, val updateTime: Long = 0 ) private val comparator = - compareByDescending<MediaSortKey> { it.data.isPlaying } - .thenByDescending { it.data.isLocalSession } - .thenByDescending { !it.data.resumption } - .thenByDescending { it.updateTime } + compareByDescending<MediaSortKey> { it.isSsMediaRec } + .thenByDescending { it.data.isPlaying } + .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() fun addMediaPlayer(key: String, data: MediaData, player: MediaControlPanel) { removeMediaPlayer(key) - val sortKey = MediaSortKey(data, System.currentTimeMillis()) + val sortKey = MediaSortKey(isSsMediaRec = false, data, System.currentTimeMillis()) + mediaData.put(key, sortKey) + mediaPlayers.put(sortKey, player) + } + + fun addMediaPlayer(key: String, player: MediaControlPanel) { + removeMediaPlayer(key) + val sortKey = MediaSortKey(isSsMediaRec = true, EMPTY, System.currentTimeMillis()) mediaData.put(key, sortKey) mediaPlayers.put(sortKey, player) } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt index bb6fbfab4c90..f0b78dde0ebd 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselScrollHandler.kt @@ -510,7 +510,7 @@ class MediaCarouselScrollHandler( * where it was and update our scroll position. */ fun onPrePlayerRemoved(removed: MediaControlPanel) { - val removedIndex = mediaContent.indexOfChild(removed.view?.player) + val removedIndex = mediaContent.indexOfChild(removed.playerViewHolder?.player) // If the removed index is less than the activeMediaIndex, then we need to decrement it. // RTL has no effect on this, because indices are always relative (start-to-end). // Update the index 'manually' since we won't always get a call to onMediaScrollingChanged diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 4fd8fe7b921b..60c08118af35 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -16,12 +16,14 @@ package com.android.systemui.media; -import static android.app.Notification.safeCharSequence; import static android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS; import android.app.PendingIntent; +import android.app.smartspace.SmartspaceAction; +import android.app.smartspace.SmartspaceTarget; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.ColorStateList; import android.graphics.Outline; import android.graphics.Rect; @@ -30,6 +32,7 @@ import android.graphics.drawable.Icon; import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.PlaybackState; +import android.os.Bundle; import android.os.SystemProperties; import android.util.Log; import android.view.View; @@ -67,6 +70,9 @@ import dagger.Lazy; public class MediaControlPanel { private static final String TAG = "MediaControlPanel"; private static final float DISABLED_ALPHA = 0.38f; + private static final String EXTRAS_MEDIA_SOURCE_LOGO = "media_source_logo"; + private static final String EXTRAS_MEDIA_SOURCE_PACKAGE_NAME = "package_name"; + private static final int MEDIA_RECOMMENDATION_MAX_NUM = 4; private final boolean mShowAppName = SystemProperties.getBoolean( "persist.sysui.qs_media_show_app_name", false); @@ -90,7 +96,8 @@ public class MediaControlPanel { private final ActivityStarter mActivityStarter; private Context mContext; - private PlayerViewHolder mViewHolder; + private PlayerViewHolder mPlayerViewHolder; + private RecommendationViewHolder mRecommendationViewHolder; private String mKey; private MediaViewController mMediaViewController; private MediaSession.Token mToken; @@ -149,13 +156,22 @@ public class MediaControlPanel { } /** - * Get the view holder used to display media controls + * Get the player view holder used to display media controls. * - * @return the view holder + * @return the player view holder */ @Nullable - public PlayerViewHolder getView() { - return mViewHolder; + public PlayerViewHolder getPlayerViewHolder() { + return mPlayerViewHolder; + } + + /** + * Get the recommendation view holder used to display Smartspace media recs. + * @return the recommendation view holder + */ + @Nullable + public RecommendationViewHolder getRecommendationViewHolder() { + return mRecommendationViewHolder; } /** @@ -189,9 +205,9 @@ public class MediaControlPanel { return mContext; } - /** Attaches the player to the view holder. */ - public void attach(PlayerViewHolder vh) { - mViewHolder = vh; + /** Attaches the player to the player view holder. */ + public void attachPlayer(PlayerViewHolder vh) { + mPlayerViewHolder = vh; TransitionLayout player = vh.getPlayer(); ImageView albumView = vh.getAlbumView(); @@ -201,9 +217,9 @@ public class MediaControlPanel { mSeekBarObserver = new SeekBarObserver(vh); mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver); mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar()); - mMediaViewController.attach(player); + mMediaViewController.attach(player, MediaViewController.TYPE.PLAYER); - mViewHolder.getPlayer().setOnLongClickListener(v -> { + mPlayerViewHolder.getPlayer().setOnLongClickListener(v -> { if (!mMediaViewController.isGutsVisible()) { mMediaViewController.openGuts(); return true; @@ -211,19 +227,25 @@ public class MediaControlPanel { return false; } }); - mViewHolder.getCancel().setOnClickListener(v -> { + mPlayerViewHolder.getCancel().setOnClickListener(v -> { closeGuts(); }); - mViewHolder.getSettings().setOnClickListener(v -> { + mPlayerViewHolder.getSettings().setOnClickListener(v -> { mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */); }); } - /** - * Bind this view based on the data given - */ - public void bind(@NonNull MediaData data, String key) { - if (mViewHolder == null) { + /** Attaches the recommendations to the recommendation view holder. */ + public void attachRecommendation(RecommendationViewHolder vh) { + mRecommendationViewHolder = vh; + TransitionLayout recommendations = vh.getRecommendations(); + + mMediaViewController.attach(recommendations, MediaViewController.TYPE.RECOMMENDATION); + } + + /** Bind this player view based on the data given. */ + public void bindPlayer(@NonNull MediaData data, String key) { + if (mPlayerViewHolder == null) { return; } mKey = key; @@ -242,20 +264,20 @@ public class MediaControlPanel { ConstraintSet expandedSet = mMediaViewController.getExpandedLayout(); ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout(); - mViewHolder.getPlayer().setBackgroundTintList( + mPlayerViewHolder.getPlayer().setBackgroundTintList( ColorStateList.valueOf(mBackgroundColor)); // Click action PendingIntent clickIntent = data.getClickIntent(); if (clickIntent != null) { - mViewHolder.getPlayer().setOnClickListener(v -> { + mPlayerViewHolder.getPlayer().setOnClickListener(v -> { if (mMediaViewController.isGutsVisible()) return; mActivityStarter.postStartActivityDismissingKeyguard(clickIntent, - buildLaunchAnimatorController(mViewHolder.getPlayer())); + buildLaunchAnimatorController(mPlayerViewHolder.getPlayer())); }); } - ImageView albumView = mViewHolder.getAlbumView(); + ImageView albumView = mPlayerViewHolder.getAlbumView(); boolean hasArtwork = data.getArtwork() != null; if (hasArtwork) { Drawable artwork = scaleDrawable(data.getArtwork()); @@ -265,7 +287,7 @@ public class MediaControlPanel { setVisibleAndAlpha(expandedSet, R.id.album_art, hasArtwork); // App icon - ImageView appIcon = mViewHolder.getAppIcon(); + ImageView appIcon = mPlayerViewHolder.getAppIcon(); if (data.getAppIcon() != null) { appIcon.setImageIcon(data.getAppIcon()); } else { @@ -273,52 +295,53 @@ public class MediaControlPanel { } // Song name - TextView titleText = mViewHolder.getTitleText(); - titleText.setText(safeCharSequence(data.getSong())); + + TextView titleText = mPlayerViewHolder.getTitleText(); + titleText.setText(data.getSong()); // App title - TextView appName = mViewHolder.getAppName(); + TextView appName = mPlayerViewHolder.getAppName(); appName.setText(data.getApp()); appName.setVisibility(mShowAppName ? View.VISIBLE : View.GONE); setVisibleAndAlpha(collapsedSet, R.id.app_name, mShowAppName); setVisibleAndAlpha(expandedSet, R.id.app_name, mShowAppName); // Artist name - TextView artistText = mViewHolder.getArtistText(); - artistText.setText(safeCharSequence(data.getArtist())); + TextView artistText = mPlayerViewHolder.getArtistText(); + artistText.setText(data.getArtist()); // Transfer chip - mViewHolder.getSeamless().setVisibility(View.VISIBLE); + mPlayerViewHolder.getSeamless().setVisibility(View.VISIBLE); setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */); setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */); - mViewHolder.getSeamless().setOnClickListener(v -> { + mPlayerViewHolder.getSeamless().setOnClickListener(v -> { mMediaOutputDialogFactory.create(data.getPackageName(), true); }); - TextView mDeviceName = mViewHolder.getSeamlessText(); + TextView mDeviceName = mPlayerViewHolder.getSeamlessText(); mDeviceName.setVisibility(mShowDeviceName ? View.VISIBLE : View.GONE); setVisibleAndAlpha(collapsedSet, R.id.media_seamless_text, mShowDeviceName); setVisibleAndAlpha(expandedSet, R.id.media_seamless_text, mShowDeviceName); - ImageView iconView = mViewHolder.getSeamlessIcon(); - TextView deviceName = mViewHolder.getSeamlessText(); + ImageView iconView = mPlayerViewHolder.getSeamlessIcon(); + TextView deviceName = mPlayerViewHolder.getSeamlessText(); final MediaDeviceData device = data.getDevice(); - final int seamlessId = mViewHolder.getSeamless().getId(); - final int seamlessFallbackId = mViewHolder.getSeamlessFallback().getId(); + final int seamlessId = mPlayerViewHolder.getSeamless().getId(); + final int seamlessFallbackId = mPlayerViewHolder.getSeamlessFallback().getId(); final boolean showFallback = device != null && !device.getEnabled(); final int seamlessFallbackVisibility = showFallback ? View.VISIBLE : View.GONE; - mViewHolder.getSeamlessFallback().setVisibility(seamlessFallbackVisibility); + mPlayerViewHolder.getSeamlessFallback().setVisibility(seamlessFallbackVisibility); expandedSet.setVisibility(seamlessFallbackId, seamlessFallbackVisibility); collapsedSet.setVisibility(seamlessFallbackId, seamlessFallbackVisibility); final int seamlessVisibility = showFallback ? View.GONE : View.VISIBLE; - mViewHolder.getSeamless().setVisibility(seamlessVisibility); + mPlayerViewHolder.getSeamless().setVisibility(seamlessVisibility); expandedSet.setVisibility(seamlessId, seamlessVisibility); collapsedSet.setVisibility(seamlessId, seamlessVisibility); final float seamlessAlpha = data.getResumption() ? DISABLED_ALPHA : 1.0f; expandedSet.setAlpha(seamlessId, seamlessAlpha); collapsedSet.setAlpha(seamlessId, seamlessAlpha); // Disable clicking on output switcher for resumption controls. - mViewHolder.getSeamless().setEnabled(!data.getResumption()); + mPlayerViewHolder.getSeamless().setEnabled(!data.getResumption()); if (showFallback) { iconView.setImageDrawable(null); deviceName.setText(null); @@ -346,7 +369,7 @@ public class MediaControlPanel { List<MediaAction> actionIcons = data.getActions(); for (; i < actionIcons.size() && i < ACTION_IDS.length; i++) { int actionId = ACTION_IDS[i]; - final ImageButton button = mViewHolder.getAction(actionId); + final ImageButton button = mPlayerViewHolder.getAction(actionId); MediaAction mediaAction = actionIcons.get(i); button.setImageIcon(mediaAction.getIcon()); button.setContentDescription(mediaAction.getContentDescription()); @@ -377,14 +400,14 @@ public class MediaControlPanel { // Guts label boolean isDismissible = data.isClearable(); - mViewHolder.getSettingsText().setText(isDismissible + mPlayerViewHolder.getSettingsText().setText(isDismissible ? R.string.controls_media_close_session : R.string.controls_media_active_session); // Dismiss - mViewHolder.getDismissLabel().setAlpha(isDismissible ? 1 : DISABLED_ALPHA); - mViewHolder.getDismiss().setEnabled(isDismissible); - mViewHolder.getDismiss().setOnClickListener(v -> { + mPlayerViewHolder.getDismissLabel().setAlpha(isDismissible ? 1 : DISABLED_ALPHA); + mPlayerViewHolder.getDismiss().setEnabled(isDismissible); + mPlayerViewHolder.getDismiss().setOnClickListener(v -> { if (mKey != null) { closeGuts(); mKeyguardDismissUtil.executeWhenUnlocked(() -> { @@ -436,6 +459,78 @@ public class MediaControlPanel { }; } + /** Bind this recommendation view based on the data given. */ + public void bindRecommendation( + @NonNull SmartspaceTarget target, + @NonNull int backgroundColor, + @Nullable View.OnClickListener callback) { + if (mRecommendationViewHolder == null) { + return; + } + + mRecommendationViewHolder.getRecommendations() + .setBackgroundTintList(ColorStateList.valueOf(backgroundColor)); + mBackgroundColor = backgroundColor; + + List<SmartspaceAction> mediaRecommendationList = target.getIconGrid(); + if (mediaRecommendationList == null || mediaRecommendationList.isEmpty()) { + Log.w(TAG, "Empty media recommendations"); + return; + } + + List<ImageView> mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems(); + List<ImageView> mediaLogoItems = mRecommendationViewHolder.getMediaLogoItems(); + List<Integer> mediaCoverItemsResIds = mRecommendationViewHolder.getMediaCoverItemsResIds(); + List<Integer> mediaLogoItemsResIds = mRecommendationViewHolder.getMediaLogoItemsResIds(); + ConstraintSet expandedSet = mMediaViewController.getExpandedLayout(); + ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout(); + int mediaRecommendationNum = Math.min(mediaRecommendationList.size(), + MEDIA_RECOMMENDATION_MAX_NUM); + for (int i = 0; i < mediaRecommendationNum; i++) { + SmartspaceAction recommendation = mediaRecommendationList.get(i); + if (recommendation.getIcon() == null) { + Log.w(TAG, "No media cover is provided. Skipping this item..."); + continue; + } + + // Get media source app's logo. + Bundle extras = recommendation.getExtras(); + Drawable icon = null; + if (extras != null && extras.getString(EXTRAS_MEDIA_SOURCE_PACKAGE_NAME) != null) { + // Get the logo from app's package name when applicable. + String packageName = extras.getString(EXTRAS_MEDIA_SOURCE_PACKAGE_NAME); + try { + icon = mContext.getPackageManager().getApplicationIcon( + packageName); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "No media source icon can be fetched via package name", e); + } + } else { + Log.w(TAG, "No media source icon is provided. Skipping this item..."); + continue; + } + + // Set up media source app's logo. + ImageView mediaSourceLogoImageView = mediaLogoItems.get(i); + mediaSourceLogoImageView.setImageDrawable(icon); + + // Set up media item cover. + ImageView mediaCoverImageView = mediaCoverItems.get(i); + mediaCoverImageView.setImageIcon(recommendation.getIcon()); + + // Set up the click listener if applicable. + setSmartspaceOnClickListener(mediaCoverImageView, recommendation, callback); + + setVisibleAndAlpha(expandedSet, mediaCoverItemsResIds.get(i), true); + setVisibleAndAlpha(expandedSet, mediaLogoItemsResIds.get(i), true); + setVisibleAndAlpha(collapsedSet, mediaCoverItemsResIds.get(i), true); + setVisibleAndAlpha(collapsedSet, mediaLogoItemsResIds.get(i), true); + } + + mController = null; + mMediaViewController.refreshState(); + } + /** * Close the guts for this player. * @@ -515,4 +610,24 @@ public class MediaControlPanel { set.setVisibility(actionId, visible ? ConstraintSet.VISIBLE : ConstraintSet.GONE); set.setAlpha(actionId, visible ? 1.0f : 0.0f); } + + private void setSmartspaceOnClickListener( + @NonNull View view, + @NonNull SmartspaceAction action, + @Nullable View.OnClickListener callback) { + if (view == null || action == null || action.getIntent() == null) { + Log.e(TAG, "No tap action can be set up"); + return; + } + + view.setOnClickListener(v -> { + mActivityStarter.postStartActivityDismissingKeyguard( + action.getIntent(), + 0 /* delay */, + buildLaunchAnimatorController(mRecommendationViewHolder.getRecommendations())); + if (callback != null) { + callback.onClick(v); + } + }); + } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt index aab27473d3e8..a274eabed198 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt @@ -51,6 +51,7 @@ class MediaDataFilter @Inject constructor( private val allEntries: LinkedHashMap<String, MediaData> = LinkedHashMap() // The filtered userEntries, which will be a subset of all userEntries in MediaDataManager private val userEntries: LinkedHashMap<String, MediaData> = LinkedHashMap() + private var hasSmartspace: Boolean = false init { userTracker = object : CurrentUserTracker(broadcastDispatcher) { @@ -84,6 +85,7 @@ class MediaDataFilter @Inject constructor( } override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) { + hasSmartspace = true listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data) } } @@ -98,6 +100,7 @@ class MediaDataFilter @Inject constructor( } override fun onSmartspaceMediaDataRemoved(key: String) { + hasSmartspace = false listeners.forEach { it.onSmartspaceMediaDataRemoved(key) } } @@ -136,17 +139,20 @@ class MediaDataFilter @Inject constructor( mediaKeys.forEach { mediaDataManager.setTimedOut(it, timedOut = true) } + if (hasSmartspace) { + mediaDataManager.dismissSmartspaceRecommendation() + } } /** * Are there any media notifications active? */ - fun hasActiveMedia() = userEntries.any { it.value.active } + fun hasActiveMedia() = userEntries.any { it.value.active } || hasSmartspace /** * Are there any media entries we should display? */ - fun hasAnyMedia() = userEntries.isNotEmpty() + fun hasAnyMedia() = userEntries.isNotEmpty() || hasSmartspace /** * Add a listener for filtered [MediaData] changes diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index dfd588d0406e..574ce0dffee0 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -424,6 +424,20 @@ class MediaDataManager( foregroundExecutor.executeDelayed({ removeEntry(key) }, delay) } + /** + * Called whenever the recommendation has been expired, or swiped from QQS. + * This will make the recommendation view to not be shown anymore during this headphone + * connection session. + */ + fun dismissSmartspaceRecommendation() { + Log.d(TAG, "Dismissing Smartspace media target") + // Do not set smartspaceMediaTarget to null. So the instance is preserved during the entire + // headphone connection, and will ONLY be set to null when headphones are disconnected. + smartspaceMediaTarget?.let { + notifySmartspaceMediaDataRemoved(it.smartspaceTargetId) + } + } + private fun loadMediaDataInBgForResumption( userId: Int, desc: MediaDescription, @@ -669,6 +683,7 @@ class MediaDataManager( 0 -> { Log.d(TAG, "Empty Smartspace media target") smartspaceMediaTarget?.let { + Log.d(TAG, "Setting Smartspace media target to null") notifySmartspaceMediaDataRemoved(it.smartspaceTargetId) } smartspaceMediaTarget = null diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt index 92eeed46388d..7cfe4c4073d2 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt @@ -32,11 +32,16 @@ import javax.inject.Inject * with the view instance and keeping the media view states up to date. */ class MediaViewController @Inject constructor( - context: Context, + private val context: Context, private val configurationController: ConfigurationController, private val mediaHostStatesManager: MediaHostStatesManager ) { + /** Indicating the media view controller is for a player or recommendation. */ + enum class TYPE { + PLAYER, RECOMMENDATION + } + companion object { @JvmField val GUTS_ANIMATION_DURATION = 500L @@ -53,6 +58,7 @@ class MediaViewController @Inject constructor( private var animationDuration: Long = 0 private var animateNextStateChange: Boolean = false private val measurement = MeasurementOutput(0, 0) + private var type: TYPE = TYPE.PLAYER /** * A map containing all viewStates for all locations of this mediaState @@ -181,8 +187,6 @@ class MediaViewController @Inject constructor( private set init { - collapsedLayout.load(context, R.xml.media_collapsed) - expandedLayout.load(context, R.xml.media_expanded) mediaHostStatesManager.addController(this) layoutController.sizeChangedListener = { width: Int, height: Int -> currentWidth = width @@ -313,7 +317,11 @@ class MediaViewController @Inject constructor( return result } - private fun getKey(state: MediaHostState, guts: Boolean, result: CacheKey): CacheKey { + private fun getKey( + state: MediaHostState, + guts: Boolean, + result: CacheKey + ): CacheKey { result.apply { heightMeasureSpec = state.measurementInput?.heightMeasureSpec ?: 0 widthMeasureSpec = state.measurementInput?.widthMeasureSpec ?: 0 @@ -327,7 +335,8 @@ class MediaViewController @Inject constructor( * Attach a view to this controller. This may perform measurements if it's not available yet * and should therefore be done carefully. */ - fun attach(transitionLayout: TransitionLayout) { + fun attach(transitionLayout: TransitionLayout, type: TYPE) { + updateMediaViewControllerType(type) this.transitionLayout = transitionLayout layoutController.attach(transitionLayout) if (currentEndLocation == -1) { @@ -426,7 +435,7 @@ class MediaViewController @Inject constructor( viewState: TransitionViewState?, location: Int, outState: TransitionViewState - ) : TransitionViewState? { + ): TransitionViewState? { val result = viewState?.copy(outState) ?: return null val overrideSize = mediaHostStatesManager.carouselSizes[location] overrideSize?.let { @@ -438,6 +447,18 @@ class MediaViewController @Inject constructor( return result } + private fun updateMediaViewControllerType(type: TYPE) { + this.type = type + if (type == TYPE.PLAYER) { + collapsedLayout.load(context, R.xml.media_collapsed) + expandedLayout.load(context, R.xml.media_expanded) + } else { + collapsedLayout.load(context, R.xml.media_recommendation) + expandedLayout.load(context, R.xml.media_recommendation) + } + refreshState() + } + /** * Retrieves the [TransitionViewState] and [MediaHostState] of a [@MediaLocation]. * In the event of [location] not being visible, [locationWhenHidden] will be used instead. diff --git a/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt new file mode 100644 index 000000000000..a375771f1104 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/RecommendationViewHolder.kt @@ -0,0 +1,61 @@ +package com.android.systemui.media + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import androidx.annotation.IntegerRes +import com.android.systemui.R +import com.android.systemui.util.animation.TransitionLayout + +/** ViewHolder for a Smartspace media recommendation. */ +class RecommendationViewHolder private constructor(itemView: View) { + + val recommendations = itemView as TransitionLayout + val mediaCoverItems = listOf<ImageView>( + itemView.requireViewById(R.id.media_cover1), + itemView.requireViewById(R.id.media_cover2), + itemView.requireViewById(R.id.media_cover3), + itemView.requireViewById(R.id.media_cover4)) + val mediaLogoItems = listOf<ImageView>( + itemView.requireViewById(R.id.media_logo1), + itemView.requireViewById(R.id.media_logo2), + itemView.requireViewById(R.id.media_logo3), + itemView.requireViewById(R.id.media_logo4)) + val mediaCoverItemsResIds = listOf<@IntegerRes Int>( + R.id.media_cover1, + R.id.media_cover2, + R.id.media_cover3, + R.id.media_cover4) + val mediaLogoItemsResIds = listOf<@IntegerRes Int>( + R.id.media_logo1, + R.id.media_logo2, + R.id.media_logo3, + R.id.media_logo4) + + init { + (recommendations.background as IlluminationDrawable).let { background -> + mediaCoverItems.forEach { background.registerLightSource(it) } + mediaLogoItems.forEach { background.registerLightSource(it) } + } + } + + companion object { + /** + * Creates a PlayerViewHolder. + * + * @param inflater LayoutInflater to use to inflate the layout. + * @param parent Parent of inflated view. + */ + @JvmStatic fun create(inflater: LayoutInflater, parent: ViewGroup): + RecommendationViewHolder { + val itemView = + inflater.inflate(R.layout.smartspace_card_media, parent, /* attachToRoot= */ false) + // Because this media view (a TransitionLayout) is used to measure and layout the views + // in various states before being attached to its parent, we can't depend on the default + // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction. + itemView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE + return RecommendationViewHolder(itemView) + } + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index af677c9d9f64..73b0a6b9a11a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -210,16 +210,16 @@ public class MediaControlPanelTest : SysuiTestCase() { fun bindWhenUnattached() { val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, null, null, device, true, null) - player.bind(state, PACKAGE) + player.bindPlayer(state, PACKAGE) assertThat(player.isPlaying()).isFalse() } @Test fun bindText() { - player.attach(holder) + player.attachPlayer(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null) - player.bind(state, PACKAGE) + player.bindPlayer(state, PACKAGE) assertThat(appName.getText()).isEqualTo(APP) assertThat(titleText.getText()).isEqualTo(TITLE) assertThat(artistText.getText()).isEqualTo(ARTIST) @@ -227,10 +227,10 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindBackgroundColor() { - player.attach(holder) + player.attachPlayer(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null) - player.bind(state, PACKAGE) + player.bindPlayer(state, PACKAGE) val list = ArgumentCaptor.forClass(ColorStateList::class.java) verify(view).setBackgroundTintList(list.capture()) assertThat(list.value).isEqualTo(ColorStateList.valueOf(BG_COLOR)) @@ -238,10 +238,10 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindDevice() { - player.attach(holder) + player.attachPlayer(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null) - player.bind(state, PACKAGE) + player.bindPlayer(state, PACKAGE) assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME) assertThat(seamless.isEnabled()).isTrue() } @@ -250,10 +250,10 @@ public class MediaControlPanelTest : SysuiTestCase() { fun bindDisabledDevice() { seamless.id = 1 seamlessFallback.id = 2 - player.attach(holder) + player.attachPlayer(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, disabledDevice, true, null) - player.bind(state, PACKAGE) + player.bindPlayer(state, PACKAGE) verify(expandedSet).setVisibility(seamless.id, View.GONE) verify(expandedSet).setVisibility(seamlessFallback.id, View.VISIBLE) verify(collapsedSet).setVisibility(seamless.id, View.GONE) @@ -262,10 +262,10 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindNullDevice() { - player.attach(holder) + player.attachPlayer(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null) - player.bind(state, PACKAGE) + player.bindPlayer(state, PACKAGE) assertThat(seamless.isEnabled()).isTrue() assertThat(seamlessText.getText()).isEqualTo(context.getResources().getString( com.android.internal.R.string.ext_media_seamless_action)) @@ -273,18 +273,18 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun bindDeviceResumptionPlayer() { - player.attach(holder) + player.attachPlayer(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, device, true, null, resumption = true) - player.bind(state, PACKAGE) + player.bindPlayer(state, PACKAGE) assertThat(seamlessText.getText()).isEqualTo(DEVICE_NAME) assertThat(seamless.isEnabled()).isFalse() } @Test fun longClick_gutsClosed() { - player.attach(holder) + player.attachPlayer(holder) whenever(mediaViewController.isGutsVisible).thenReturn(false) val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java) @@ -296,7 +296,7 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun longClick_gutsOpen() { - player.attach(holder) + player.attachPlayer(holder) whenever(mediaViewController.isGutsVisible).thenReturn(true) val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java) @@ -308,7 +308,7 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun cancelButtonClick_animation() { - player.attach(holder) + player.attachPlayer(holder) cancel.callOnClick() @@ -317,7 +317,7 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun settingsButtonClick() { - player.attach(holder) + player.attachPlayer(holder) settings.callOnClick() @@ -330,11 +330,11 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun dismissButtonClick() { val mediaKey = "key for dismissal" - player.attach(holder) + player.attachPlayer(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null, notificationKey = KEY) - player.bind(state, mediaKey) + player.bindPlayer(state, mediaKey) assertThat(dismiss.isEnabled).isEqualTo(true) dismiss.callOnClick() @@ -348,11 +348,11 @@ public class MediaControlPanelTest : SysuiTestCase() { @Test fun dismissButtonDisabled() { val mediaKey = "key for dismissal" - player.attach(holder) + player.attachPlayer(holder) val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(), emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null, isClearable = false, notificationKey = KEY) - player.bind(state, mediaKey) + player.bindPlayer(state, mediaKey) assertThat(dismiss.isEnabled).isEqualTo(false) } |