diff options
3 files changed, 243 insertions, 125 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 60c2ed2fa2be..c3a7d9fbdd50 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -37,9 +37,7 @@ import android.media.session.MediaSession; import android.media.session.PlaybackState; import android.service.media.MediaBrowserService; import android.util.Log; -import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; @@ -90,16 +88,14 @@ public class MediaControlPanel { }; private final SeekBarViewModel mSeekBarViewModel; - private final SeekBarObserver mSeekBarObserver; + private SeekBarObserver mSeekBarObserver; private final Executor mForegroundExecutor; protected final Executor mBackgroundExecutor; private final ActivityStarter mActivityStarter; - private final LayoutAnimationHelper mLayoutAnimationHelper; + private LayoutAnimationHelper mLayoutAnimationHelper; private Context mContext; - private MotionLayout mMediaNotifView; - private final View mBackground; - private View mSeamless; + private PlayerViewHolder mViewHolder; private MediaSession.Token mToken; private MediaController mController; private int mForegroundColor; @@ -107,7 +103,7 @@ public class MediaControlPanel { private MediaDevice mDevice; protected ComponentName mServiceComponent; private boolean mIsRegistered = false; - private final List<KeyFrames> mKeyFrames; + private List<KeyFrames> mKeyFrames; private String mKey; private int mAlbumArtSize; private int mAlbumArtRadius; @@ -166,37 +162,27 @@ public class MediaControlPanel { /** * Initialize a new control panel * @param context - * @param parent * @param routeManager Manager used to listen for device change events. * @param foregroundExecutor foreground executor * @param backgroundExecutor background executor, used for processing artwork * @param activityStarter activity starter */ - public MediaControlPanel(Context context, ViewGroup parent, - @Nullable LocalMediaManager routeManager, Executor foregroundExecutor, - DelayableExecutor backgroundExecutor, ActivityStarter activityStarter) { + public MediaControlPanel(Context context, @Nullable LocalMediaManager routeManager, + Executor foregroundExecutor, DelayableExecutor backgroundExecutor, + ActivityStarter activityStarter) { mContext = context; - LayoutInflater inflater = LayoutInflater.from(mContext); - mMediaNotifView = (MotionLayout) inflater.inflate(R.layout.qs_media_panel, parent, false); - mBackground = mMediaNotifView.findViewById(R.id.media_background); - mLayoutAnimationHelper = new LayoutAnimationHelper(mMediaNotifView); - GoneChildrenHideHelper.clipGoneChildrenOnLayout(mMediaNotifView); - mKeyFrames = mMediaNotifView.getDefinedTransitions().get(0).getKeyFrameList(); mLocalMediaManager = routeManager; mForegroundExecutor = foregroundExecutor; mBackgroundExecutor = backgroundExecutor; mActivityStarter = activityStarter; mSeekBarViewModel = new SeekBarViewModel(backgroundExecutor); - mSeekBarObserver = new SeekBarObserver(getView()); - mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver); - SeekBar bar = getView().findViewById(R.id.media_progress_bar); - bar.setOnSeekBarChangeListener(mSeekBarViewModel.getSeekBarListener()); - bar.setOnTouchListener(mSeekBarViewModel.getSeekBarTouchListener()); loadDimens(); } public void onDestroy() { - mSeekBarViewModel.getProgress().removeObserver(mSeekBarObserver); + if (mSeekBarObserver != null) { + mSeekBarViewModel.getProgress().removeObserver(mSeekBarObserver); + } makeInactive(); } @@ -207,11 +193,12 @@ public class MediaControlPanel { } /** - * Get the view used to display media controls - * @return the view + * Get the view holder used to display media controls + * @return the view holder */ - public MotionLayout getView() { - return mMediaNotifView; + @Nullable + public PlayerViewHolder getView() { + return mViewHolder; } /** @@ -234,10 +221,27 @@ public class MediaControlPanel { return mContext; } + /** Attaches the player to the view holder. */ + public void attach(PlayerViewHolder vh) { + mViewHolder = vh; + MotionLayout motionView = vh.getPlayer(); + mLayoutAnimationHelper = new LayoutAnimationHelper(motionView); + GoneChildrenHideHelper.clipGoneChildrenOnLayout(motionView); + mKeyFrames = motionView.getDefinedTransitions().get(0).getKeyFrameList(); + mSeekBarObserver = new SeekBarObserver(motionView); + mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver); + SeekBar bar = vh.getSeekBar(); + bar.setOnSeekBarChangeListener(mSeekBarViewModel.getSeekBarListener()); + bar.setOnTouchListener(mSeekBarViewModel.getSeekBarTouchListener()); + } + /** * Bind this view based on the data given */ public void bind(@NotNull MediaData data) { + if (mViewHolder == null) { + return; + } MediaSession.Token token = data.getToken(); mForegroundColor = data.getForegroundColor(); mBackgroundColor = data.getBackgroundColor(); @@ -254,8 +258,8 @@ public class MediaControlPanel { mController = new MediaController(mContext, mToken); - ConstraintSet expandedSet = mMediaNotifView.getConstraintSet(R.id.expanded); - ConstraintSet collapsedSet = mMediaNotifView.getConstraintSet(R.id.collapsed); + ConstraintSet expandedSet = mViewHolder.getPlayer().getConstraintSet(R.id.expanded); + ConstraintSet collapsedSet = mViewHolder.getPlayer().getConstraintSet(R.id.collapsed); // Try to find a browser service component for this app // TODO also check for a media button receiver intended for restarting (b/154127084) @@ -281,64 +285,61 @@ public class MediaControlPanel { mController.registerCallback(mSessionCallback); - mMediaNotifView.requireViewById(R.id.media_background).setBackgroundTintList( + mViewHolder.getBackground().setBackgroundTintList( ColorStateList.valueOf(mBackgroundColor)); // Click action PendingIntent clickIntent = data.getClickIntent(); if (clickIntent != null) { - mMediaNotifView.setOnClickListener(v -> { + mViewHolder.getPlayer().setOnClickListener(v -> { mActivityStarter.postStartActivityDismissingKeyguard(clickIntent); }); } - ImageView albumView = mMediaNotifView.findViewById(R.id.album_art); + ImageView albumView = mViewHolder.getAlbumView(); // TODO: migrate this to a view with rounded corners instead of baking the rounding // into the bitmap Drawable artwork = createRoundedBitmap(data.getArtwork()); albumView.setImageDrawable(artwork); // App icon - ImageView appIcon = mMediaNotifView.requireViewById(R.id.icon); + ImageView appIcon = mViewHolder.getAppIcon(); Drawable iconDrawable = data.getAppIcon().mutate(); iconDrawable.setTint(mForegroundColor); appIcon.setImageDrawable(iconDrawable); // Song name - TextView titleText = mMediaNotifView.requireViewById(R.id.header_title); + TextView titleText = mViewHolder.getTitleText(); titleText.setText(data.getSong()); titleText.setTextColor(data.getForegroundColor()); // App title - TextView appName = mMediaNotifView.requireViewById(R.id.app_name); + TextView appName = mViewHolder.getAppName(); appName.setText(data.getApp()); appName.setTextColor(mForegroundColor); // Artist name - TextView artistText = mMediaNotifView.requireViewById(R.id.header_artist); + TextView artistText = mViewHolder.getArtistText(); artistText.setText(data.getArtist()); artistText.setTextColor(mForegroundColor); // Transfer chip - mSeamless = mMediaNotifView.findViewById(R.id.media_seamless); - if (mSeamless != null) { - if (mLocalMediaManager != null) { - mSeamless.setVisibility(View.VISIBLE); - setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */); - setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */); - updateDevice(mLocalMediaManager.getCurrentConnectedDevice()); - mSeamless.setOnClickListener(v -> { - final Intent intent = new Intent() - .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) - .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, - mController.getPackageName()) - .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, mToken); - mActivityStarter.startActivity(intent, false, true /* dismissShade */, - Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); - }); - } else { - Log.d(TAG, "LocalMediaManager is null. Not binding output chip for pkg=" + pkgName); - } + if (mLocalMediaManager != null) { + mViewHolder.getSeamless().setVisibility(View.VISIBLE); + setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */); + setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */); + updateDevice(mLocalMediaManager.getCurrentConnectedDevice()); + mViewHolder.getSeamless().setOnClickListener(v -> { + final Intent intent = new Intent() + .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) + .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME, + mController.getPackageName()) + .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, mToken); + mActivityStarter.startActivity(intent, false, true /* dismissShade */, + Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + }); + } else { + Log.d(TAG, "LocalMediaManager is null. Not binding output chip for pkg=" + pkgName); } PlaybackInfo playbackInfo = mController.getPlaybackInfo(); if (playbackInfo != null) { @@ -353,16 +354,16 @@ 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 = mMediaNotifView.findViewById(actionId); + final ImageButton button = mViewHolder.getAction(actionId); MediaAction mediaAction = actionIcons.get(i); button.setImageDrawable(mediaAction.getDrawable()); button.setContentDescription(mediaAction.getContentDescription()); button.setImageTintList(ColorStateList.valueOf(mForegroundColor)); PendingIntent actionIntent = mediaAction.getIntent(); - if (mBackground.getBackground() instanceof IlluminationDrawable) { - ((IlluminationDrawable) mBackground.getBackground()) - .setupTouch(button, mMediaNotifView); + if (mViewHolder.getBackground().getBackground() instanceof IlluminationDrawable) { + ((IlluminationDrawable) mViewHolder.getBackground().getBackground()) + .setupTouch(button, mViewHolder.getPlayer()); } button.setOnClickListener(v -> { @@ -397,8 +398,8 @@ public class MediaControlPanel { makeActive(); // Update both constraint sets to regenerate the animation. - mMediaNotifView.updateState(R.id.collapsed, collapsedSet); - mMediaNotifView.updateState(R.id.expanded, expandedSet); + mViewHolder.getPlayer().updateState(R.id.collapsed, collapsedSet); + mViewHolder.getPlayer().updateState(R.id.expanded, expandedSet); } @UiThread @@ -441,6 +442,9 @@ public class MediaControlPanel { * @param visible is the view visible */ private void updateKeyFrameVisibility(int actionId, boolean visible) { + if (mKeyFrames == null) { + return; + } for (int i = 0; i < mKeyFrames.size(); i++) { KeyFrames keyframe = mKeyFrames.get(i); ArrayList<Key> viewKeyFrames = keyframe.getKeyFramesForView(actionId); @@ -528,38 +532,38 @@ public class MediaControlPanel { * @param device device information to display */ private void updateDevice(MediaDevice device) { - if (mSeamless == null) { - return; - } mForegroundExecutor.execute(() -> { updateChipInternal(device); }); } private void updateChipInternal(MediaDevice device) { + if (mViewHolder == null) { + return; + } ColorStateList fgTintList = ColorStateList.valueOf(mForegroundColor); // Update the outline color - LinearLayout viewLayout = (LinearLayout) mSeamless; + LinearLayout viewLayout = (LinearLayout) mViewHolder.getSeamless(); RippleDrawable bkgDrawable = (RippleDrawable) viewLayout.getBackground(); GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0); rect.setStroke(2, mForegroundColor); rect.setColor(mBackgroundColor); - ImageView iconView = mSeamless.findViewById(R.id.media_seamless_image); - TextView deviceName = mSeamless.findViewById(R.id.media_seamless_text); + ImageView iconView = mViewHolder.getSeamlessIcon(); + TextView deviceName = mViewHolder.getSeamlessText(); deviceName.setTextColor(fgTintList); if (mIsRemotePlayback) { - mSeamless.setEnabled(false); - mSeamless.setAlpha(0.38f); + mViewHolder.getSeamless().setEnabled(false); + mViewHolder.getSeamless().setAlpha(0.38f); iconView.setImageResource(R.drawable.ic_hardware_speaker); iconView.setVisibility(View.VISIBLE); iconView.setImageTintList(fgTintList); deviceName.setText(R.string.media_seamless_remote_device); } else if (device != null) { - mSeamless.setEnabled(true); - mSeamless.setAlpha(1f); + mViewHolder.getSeamless().setEnabled(true); + mViewHolder.getSeamless().setAlpha(1f); Drawable icon = device.getIcon(); iconView.setVisibility(View.VISIBLE); iconView.setImageTintList(fgTintList); @@ -575,8 +579,8 @@ public class MediaControlPanel { } else { // Reset to default Log.d(TAG, "device is null. Not binding output chip."); - mSeamless.setEnabled(true); - mSeamless.setAlpha(1f); + mViewHolder.getSeamless().setEnabled(true); + mViewHolder.getSeamless().setAlpha(1f); iconView.setVisibility(View.GONE); deviceName.setText(com.android.internal.R.string.ext_media_seamless_action); } @@ -601,17 +605,20 @@ public class MediaControlPanel { * Hide the media buttons and show only a restart button */ protected void resetButtons() { + if (mViewHolder == null) { + return; + } // Hide all the old buttons - ConstraintSet expandedSet = mMediaNotifView.getConstraintSet(R.id.expanded); - ConstraintSet collapsedSet = mMediaNotifView.getConstraintSet(R.id.collapsed); + ConstraintSet expandedSet = mViewHolder.getPlayer().getConstraintSet(R.id.expanded); + ConstraintSet collapsedSet = mViewHolder.getPlayer().getConstraintSet(R.id.collapsed); for (int i = 1; i < ACTION_IDS.length; i++) { setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /*visible */); setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */); } // Add a restart button - ImageButton btn = mMediaNotifView.findViewById(ACTION_IDS[0]); + ImageButton btn = mViewHolder.getAction0(); btn.setOnClickListener(v -> { Log.d(TAG, "Attempting to restart session"); if (mQSMediaBrowser != null) { @@ -639,9 +646,9 @@ public class MediaControlPanel { mSeekBarViewModel.clearController(); // TODO: fix guts // View guts = mMediaNotifView.findViewById(R.id.media_guts); - View options = mMediaNotifView.findViewById(R.id.qs_media_controls_options); + View options = mViewHolder.getOptions(); - mMediaNotifView.setOnLongClickListener(v -> { + mViewHolder.getPlayer().setOnLongClickListener(v -> { // Replace player view with close/cancel view // guts.setVisibility(View.GONE); options.setVisibility(View.VISIBLE); @@ -748,20 +755,28 @@ public class MediaControlPanel { protected void removePlayer() { } public void measure(@Nullable MediaMeasurementInput input) { + if (mViewHolder == null) { + return; + } if (input != null) { int width = input.getWidth(); setPlayerWidth(width); - mMediaNotifView.measure(input.getWidthMeasureSpec(), input.getHeightMeasureSpec()); + mViewHolder.getPlayer().measure(input.getWidthMeasureSpec(), + input.getHeightMeasureSpec()); } } public void setPlayerWidth(int width) { - ConstraintSet expandedSet = mMediaNotifView.getConstraintSet(R.id.expanded); - ConstraintSet collapsedSet = mMediaNotifView.getConstraintSet(R.id.collapsed); + if (mViewHolder == null) { + return; + } + MotionLayout view = mViewHolder.getPlayer(); + ConstraintSet expandedSet = view.getConstraintSet(R.id.expanded); + ConstraintSet collapsedSet = view.getConstraintSet(R.id.collapsed); collapsedSet.setGuidelineBegin(R.id.view_width, width); expandedSet.setGuidelineBegin(R.id.view_width, width); - mMediaNotifView.updateState(R.id.collapsed, collapsedSet); - mMediaNotifView.updateState(R.id.expanded, expandedSet); + view.updateState(R.id.collapsed, collapsedSet); + view.updateState(R.id.expanded, expandedSet); } public void animatePendingSizeChange(long duration, long startDelay) { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt index 49d2d8860a2f..9c92b0a27c03 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewManager.kt @@ -56,8 +56,13 @@ class MediaViewManager @Inject constructor( } } private val scrollChangedListener = object : View.OnScrollChangeListener { - override fun onScrollChange(v: View?, scrollX: Int, scrollY: Int, oldScrollX: Int, - oldScrollY: Int) { + override fun onScrollChange( + v: View?, + scrollX: Int, + scrollY: Int, + oldScrollX: Int, + oldScrollY: Int + ) { if (playerWidthPlusPadding == 0) { return } @@ -79,16 +84,17 @@ class MediaViewManager @Inject constructor( override fun onMediaDataRemoved(key: String) { val removed = mediaPlayers.remove(key) removed?.apply { - val beforeActive = mediaContent.indexOfChild(removed.view) <= activeMediaIndex - mediaContent.removeView(removed.view) + val beforeActive = mediaContent.indexOfChild(removed.view?.player) <= + activeMediaIndex + mediaContent.removeView(removed.view?.player) removed.onDestroy() updateMediaPaddings() if (beforeActive) { // also update the index here since the scroll below might not always lead // to a scrolling changed activeMediaIndex = Math.max(0, activeMediaIndex - 1) - mediaCarousel.scrollX = Math.max(mediaCarousel.scrollX - - playerWidthPlusPadding, 0) + mediaCarousel.scrollX = Math.max(mediaCarousel.scrollX - + playerWidthPlusPadding, 0) } updatePlayerVisibilities() } @@ -103,7 +109,7 @@ class MediaViewManager @Inject constructor( private fun reorderAllPlayers() { for (mediaPlayer in mediaPlayers.values) { - val view = mediaPlayer.view + val view = mediaPlayer.view?.player if (mediaPlayer.isPlaying && mediaContent.indexOfChild(view) != 0) { mediaContent.removeView(view) mediaContent.addView(view, 0) @@ -142,24 +148,26 @@ class MediaViewManager @Inject constructor( val routeManager = LocalMediaManager(context, localBluetoothManager, imm, data.packageName) - existingPlayer = MediaControlPanel(context, mediaContent, routeManager, - foregroundExecutor, backgroundExecutor, activityStarter) + existingPlayer = MediaControlPanel(context, routeManager, foregroundExecutor, + backgroundExecutor, activityStarter) + existingPlayer.attach(PlayerViewHolder.create(LayoutInflater.from(context), + mediaContent)) mediaPlayers[key] = existingPlayer val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT) - existingPlayer.view.setLayoutParams(lp) + existingPlayer.view?.player?.setLayoutParams(lp) existingPlayer.setListening(currentlyExpanded) if (existingPlayer.isPlaying) { - mediaContent.addView(existingPlayer.view, 0) + mediaContent.addView(existingPlayer.view?.player, 0) } else { - mediaContent.addView(existingPlayer.view) + mediaContent.addView(existingPlayer.view?.player) } updatePlayerToCurrentState(existingPlayer) } else if (existingPlayer.isPlaying && - mediaContent.indexOfChild(existingPlayer.view) != 0) { + mediaContent.indexOfChild(existingPlayer.view?.player) != 0) { if (visualStabilityManager.isReorderingAllowed) { - mediaContent.removeView(existingPlayer.view) - mediaContent.addView(existingPlayer.view, 0) + mediaContent.removeView(existingPlayer.view?.player) + mediaContent.addView(existingPlayer.view?.player, 0) } else { visualStabilityManager.addReorderingAllowedCallback(visualStabilityCallback) } @@ -167,7 +175,7 @@ class MediaViewManager @Inject constructor( existingPlayer.bind(data) // Resetting the progress to make sure it's taken into account for the latest // motion model - existingPlayer.view.progress = currentState?.expansion ?: 0.0f + existingPlayer.view?.player?.progress = currentState?.expansion ?: 0.0f updateMediaPaddings() } @@ -190,7 +198,6 @@ class MediaViewManager @Inject constructor( mediaView.layoutParams = layoutParams } } - } /** @@ -201,8 +208,8 @@ class MediaViewManager @Inject constructor( currentState = state currentlyExpanded = state.expansion > 0 for (mediaPlayer in mediaPlayers.values) { - val view = mediaPlayer.view - view.progress = state.expansion + val view = mediaPlayer.view?.player + view?.progress = state.expansion } } @@ -215,8 +222,12 @@ class MediaViewManager @Inject constructor( * @param desiredState the target state we're transitioning to * @param animate should this be animated */ - fun onDesiredLocationChanged(desiredState: MediaState?, animate: Boolean, duration: Long, - startDelay: Long) { + fun onDesiredLocationChanged( + desiredState: MediaState?, + animate: Boolean, + duration: Long, + startDelay: Long + ) { if (desiredState is MediaHost.MediaHostState) { // This is a hosting view, let's remeasure our players this.desiredState = desiredState @@ -224,7 +235,7 @@ class MediaViewManager @Inject constructor( if (playerWidth != width) { setPlayerWidth(width) for (mediaPlayer in mediaPlayers.values) { - if (animate && mediaPlayer.view.visibility == View.VISIBLE) { + if (animate && mediaPlayer.view?.player?.visibility == View.VISIBLE) { mediaPlayer.animatePendingSizeChange(duration, startDelay) } } @@ -266,24 +277,25 @@ class MediaViewManager @Inject constructor( * Get a measurement for the given input state. This measures the first player and returns * its bounds as if it were measured with the given measurement dimensions */ - fun obtainMeasurement(input: MediaMeasurementInput) : MeasurementOutput? { + fun obtainMeasurement(input: MediaMeasurementInput): MeasurementOutput? { val firstPlayer = mediaPlayers.values.firstOrNull() ?: return null - // Let's measure the size of the first player and return its height - val previousProgress = firstPlayer.view.progress - val previousRight = firstPlayer.view.right - val previousBottom = firstPlayer.view.bottom - firstPlayer.view.progress = input.expansion - firstPlayer.measure(input) - // Relayouting is necessary in motionlayout to obtain its size properly .... - firstPlayer.view.layout(0, 0, firstPlayer.view.measuredWidth, - firstPlayer.view.measuredHeight) - val result = MeasurementOutput(firstPlayer.view.measuredWidth, - firstPlayer.view.measuredHeight) - firstPlayer.view.progress = previousProgress - if (desiredState != null) { - // remeasure it to the old size again! - firstPlayer.measure(desiredState!!.measurementInput) - firstPlayer.view.layout(0, 0, previousRight, previousBottom) + var result: MeasurementOutput? = null + firstPlayer.view?.player?.let { + // Let's measure the size of the first player and return its height + val previousProgress = it.progress + val previousRight = it.right + val previousBottom = it.bottom + it.progress = input.expansion + firstPlayer.measure(input) + // Relayouting is necessary in motionlayout to obtain its size properly .... + it.layout(0, 0, it.measuredWidth, it.measuredHeight) + val result = MeasurementOutput(it.measuredWidth, it.measuredHeight) + it.progress = previousProgress + if (desiredState != null) { + // remeasure it to the old size again! + firstPlayer.measure(desiredState!!.measurementInput) + it.layout(0, 0, previousRight, previousBottom) + } } return result } @@ -295,8 +307,8 @@ class MediaViewManager @Inject constructor( val widthSpec = desiredState!!.measurementInput?.widthMeasureSpec ?: 0 val heightSpec = desiredState!!.measurementInput?.heightMeasureSpec ?: 0 for (mediaPlayer in mediaPlayers.values) { - mediaPlayer.view.measure(widthSpec, heightSpec) + mediaPlayer.view?.player?.measure(widthSpec, heightSpec) } } } -}
\ No newline at end of file +} diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt new file mode 100644 index 000000000000..571e18d0ff20 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package com.android.systemui.media + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageButton +import android.widget.ImageView +import android.widget.SeekBar +import android.widget.TextView + +import androidx.constraintlayout.motion.widget.MotionLayout + +import com.android.systemui.R + +/** + * ViewHolder for a media player. + */ +class PlayerViewHolder private constructor(itemView: View) { + + val player = itemView as MotionLayout + val background = itemView.requireViewById<View>(R.id.media_background) + + // Player information + val appIcon = itemView.requireViewById<ImageView>(R.id.icon) + val appName = itemView.requireViewById<TextView>(R.id.app_name) + val albumView = itemView.requireViewById<ImageView>(R.id.album_art) + val titleText = itemView.requireViewById<TextView>(R.id.header_title) + val artistText = itemView.requireViewById<TextView>(R.id.header_artist) + + // Output switcher + val seamless = itemView.findViewById<ViewGroup>(R.id.media_seamless) + val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image) + val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text) + + // Seek bar + val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar) + val elapsedTimeView = itemView.requireViewById<TextView>(R.id.media_elapsed_time) + val totalTimeView = itemView.requireViewById<TextView>(R.id.media_total_time) + + // Action Buttons + val action0 = itemView.requireViewById<ImageButton>(R.id.action0) + val action1 = itemView.requireViewById<ImageButton>(R.id.action1) + val action2 = itemView.requireViewById<ImageButton>(R.id.action2) + val action3 = itemView.requireViewById<ImageButton>(R.id.action3) + val action4 = itemView.requireViewById<ImageButton>(R.id.action4) + + fun getAction(id: Int): ImageButton { + return when (id) { + R.id.action0 -> action0 + R.id.action1 -> action1 + R.id.action2 -> action2 + R.id.action3 -> action3 + R.id.action4 -> action4 + else -> { + throw IllegalArgumentException() + } + } + } + + // Settings screen + val options = itemView.requireViewById<View>(R.id.qs_media_controls_options) + + 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): PlayerViewHolder { + val v = inflater.inflate(R.layout.qs_media_panel, parent, false) + return PlayerViewHolder(v) + } + } +} |