Towards paged layout: introduce view holder
Bug: 153170704
Test: Check that player + correct elements appear in QS, QQS and LS.
Change-Id: Id4792f263b405cb4e2f4cb424443db03bacd0a34
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 60c2ed2..c3a7d9f 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.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 @@
};
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 @@
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 @@
/**
* 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 @@
}
/**
- * 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
* @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 @@
* @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 @@
} 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 @@
* 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 @@
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 @@
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 49d2d88..9c92b0a2 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 @@
}
}
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 @@
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 @@
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 @@
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 @@
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 @@
mediaView.layoutParams = layoutParams
}
}
-
}
/**
@@ -201,8 +208,8 @@
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 @@
* @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 @@
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 @@
* 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 @@
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 0000000..571e18d
--- /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)
+ }
+ }
+}