blob: 3fc162ead6d1eecc607f92a55bff9f6736e02b84 [file] [log] [blame]
Beth Thibodeau7b6c1782020-03-05 11:43:51 -05001/*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.media;
18
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050019import android.app.PendingIntent;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050020import android.content.Context;
21import android.content.Intent;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050022import android.content.res.ColorStateList;
Fabian Kozynski47714a92020-06-17 10:22:35 -040023import android.graphics.Outline;
Selim Cinekc5436712020-04-27 15:15:44 -070024import android.graphics.Rect;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050025import android.graphics.drawable.Drawable;
Selim Cinekc5436712020-04-27 15:15:44 -070026import android.graphics.drawable.Icon;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050027import android.media.session.MediaController;
28import android.media.session.MediaSession;
29import android.media.session.PlaybackState;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050030import android.util.Log;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050031import android.view.View;
Fabian Kozynski47714a92020-06-17 10:22:35 -040032import android.view.ViewOutlineProvider;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050033import android.widget.ImageButton;
34import android.widget.ImageView;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050035import android.widget.TextView;
36
Selim Cinek2de5ebb2020-05-20 15:39:03 -070037import androidx.annotation.NonNull;
Robert Snoeberger9a7409b2020-04-09 18:12:27 -040038import androidx.annotation.Nullable;
Selim Cinekf418bb02020-05-04 17:16:58 -070039import androidx.annotation.UiThread;
Selim Cinek5dbef2d2020-05-07 17:44:38 -070040import androidx.constraintlayout.widget.ConstraintSet;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050041
Selim Cinekc5436712020-04-27 15:15:44 -070042import com.android.settingslib.Utils;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050043import com.android.settingslib.media.MediaOutputSliceConstants;
44import com.android.settingslib.widget.AdaptiveIcon;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050045import com.android.systemui.R;
Robert Snoeberger7cec5422020-05-29 17:09:14 -040046import com.android.systemui.dagger.qualifiers.Background;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050047import com.android.systemui.plugins.ActivityStarter;
Selim Cinek2de5ebb2020-05-20 15:39:03 -070048import com.android.systemui.util.animation.TransitionLayout;
Selim Cinek5dbef2d2020-05-07 17:44:38 -070049
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050050import java.util.List;
51import java.util.concurrent.Executor;
52
Robert Snoeberger7cec5422020-05-29 17:09:14 -040053import javax.inject.Inject;
54
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050055/**
Selim Cinekd8357922020-04-10 15:06:53 -070056 * A view controller used for Media Playback.
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050057 */
Robert Snoeberger3cc22222020-03-25 15:36:31 -040058public class MediaControlPanel {
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050059 private static final String TAG = "MediaControlPanel";
Robert Snoebergerf05aa68f2020-06-18 16:14:29 -040060 private static final float DISABLED_ALPHA = 0.38f;
Selim Cinek5dbef2d2020-05-07 17:44:38 -070061
62 // Button IDs for QS controls
63 static final int[] ACTION_IDS = {
64 R.id.action0,
65 R.id.action1,
66 R.id.action2,
67 R.id.action3,
68 R.id.action4
69 };
70
71 private final SeekBarViewModel mSeekBarViewModel;
Robert Snoebergereb49e942020-05-12 16:31:09 -040072 private SeekBarObserver mSeekBarObserver;
Beth Thibodeau23a33ab2020-04-07 20:51:57 -040073 protected final Executor mBackgroundExecutor;
Beth Thibodeaue561c002020-04-23 17:33:00 -040074 private final ActivityStarter mActivityStarter;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050075
76 private Context mContext;
Robert Snoebergereb49e942020-05-12 16:31:09 -040077 private PlayerViewHolder mViewHolder;
Selim Cinek2de5ebb2020-05-20 15:39:03 -070078 private MediaViewController mMediaViewController;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050079 private MediaSession.Token mToken;
80 private MediaController mController;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050081 private int mBackgroundColor;
Selim Cinekc5436712020-04-27 15:15:44 -070082 private int mAlbumArtSize;
83 private int mAlbumArtRadius;
Fabian Kozynski47714a92020-06-17 10:22:35 -040084 // This will provide the corners for the album art.
85 private final ViewOutlineProvider mViewOutlineProvider;
Robert Snoeberger9a7409b2020-04-09 18:12:27 -040086
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050087 /**
88 * Initialize a new control panel
89 * @param context
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050090 * @param backgroundExecutor background executor, used for processing artwork
Beth Thibodeaue561c002020-04-23 17:33:00 -040091 * @param activityStarter activity starter
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050092 */
Robert Snoeberger7cec5422020-05-29 17:09:14 -040093 @Inject
94 public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
Lucas Dupin84f5a0e2020-06-08 19:55:33 -070095 ActivityStarter activityStarter, MediaViewController mediaViewController,
Robert Snoeberger7cec5422020-05-29 17:09:14 -040096 SeekBarViewModel seekBarViewModel) {
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050097 mContext = context;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050098 mBackgroundExecutor = backgroundExecutor;
Beth Thibodeaue561c002020-04-23 17:33:00 -040099 mActivityStarter = activityStarter;
Robert Snoeberger7cec5422020-05-29 17:09:14 -0400100 mSeekBarViewModel = seekBarViewModel;
Lucas Dupin84f5a0e2020-06-08 19:55:33 -0700101 mMediaViewController = mediaViewController;
Selim Cinekc5436712020-04-27 15:15:44 -0700102 loadDimens();
Fabian Kozynski47714a92020-06-17 10:22:35 -0400103
104 mViewOutlineProvider = new ViewOutlineProvider() {
105 @Override
106 public void getOutline(View view, Outline outline) {
107 outline.setRoundRect(0, 0, mAlbumArtSize, mAlbumArtSize, mAlbumArtRadius);
108 }
109 };
Selim Cinekc5436712020-04-27 15:15:44 -0700110 }
111
Selim Cinek098baf42020-04-27 19:02:06 -0700112 public void onDestroy() {
Robert Snoebergereb49e942020-05-12 16:31:09 -0400113 if (mSeekBarObserver != null) {
114 mSeekBarViewModel.getProgress().removeObserver(mSeekBarObserver);
115 }
Robert Snoeberger734463e2020-05-20 02:10:56 -0400116 mSeekBarViewModel.onDestroy();
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700117 mMediaViewController.onDestroy();
Selim Cinek098baf42020-04-27 19:02:06 -0700118 }
119
Selim Cinekc5436712020-04-27 15:15:44 -0700120 private void loadDimens() {
121 mAlbumArtRadius = mContext.getResources().getDimensionPixelSize(
122 Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
123 mAlbumArtSize = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_album_size);
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500124 }
125
126 /**
Robert Snoebergereb49e942020-05-12 16:31:09 -0400127 * Get the view holder used to display media controls
128 * @return the view holder
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500129 */
Robert Snoebergereb49e942020-05-12 16:31:09 -0400130 @Nullable
131 public PlayerViewHolder getView() {
132 return mViewHolder;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500133 }
134
135 /**
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700136 * Get the view controller used to display media controls
137 * @return the media view controller
138 */
139 @NonNull
140 public MediaViewController getMediaViewController() {
141 return mMediaViewController;
142 }
143
144 /**
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700145 * Sets the listening state of the player.
146 *
147 * Should be set to true when the QS panel is open. Otherwise, false. This is a signal to avoid
148 * unnecessary work when the QS panel is closed.
149 *
150 * @param listening True when player should be active. Otherwise, false.
151 */
152 public void setListening(boolean listening) {
153 mSeekBarViewModel.setListening(listening);
154 }
155
156 /**
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500157 * Get the context
158 * @return context
159 */
160 public Context getContext() {
161 return mContext;
162 }
163
Robert Snoebergereb49e942020-05-12 16:31:09 -0400164 /** Attaches the player to the view holder. */
165 public void attach(PlayerViewHolder vh) {
166 mViewHolder = vh;
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700167 TransitionLayout player = vh.getPlayer();
Fabian Kozynski47714a92020-06-17 10:22:35 -0400168
169 ImageView albumView = vh.getAlbumView();
170 albumView.setOutlineProvider(mViewOutlineProvider);
171 albumView.setClipToOutline(true);
172
Robert Snoeberger45be3fb2020-05-19 02:00:43 -0400173 mSeekBarObserver = new SeekBarObserver(vh);
Robert Snoebergereb49e942020-05-12 16:31:09 -0400174 mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
Robert Snoeberger77d3dca2020-06-02 17:36:49 -0400175 mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700176 mMediaViewController.attach(player);
Robert Snoebergereb49e942020-05-12 16:31:09 -0400177 }
178
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500179 /**
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700180 * Bind this view based on the data given
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500181 */
Fabian Kozynski47714a92020-06-17 10:22:35 -0400182 public void bind(@NonNull MediaData data) {
Robert Snoebergereb49e942020-05-12 16:31:09 -0400183 if (mViewHolder == null) {
184 return;
185 }
Selim Cinekf0f74952020-04-21 11:45:16 -0700186 MediaSession.Token token = data.getToken();
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700187 mBackgroundColor = data.getBackgroundColor();
Beth Thibodeau23a33ab2020-04-07 20:51:57 -0400188 if (mToken == null || !mToken.equals(token)) {
189 mToken = token;
Beth Thibodeau23a33ab2020-04-07 20:51:57 -0400190 }
191
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400192 if (mToken != null) {
193 mController = new MediaController(mContext, mToken);
194 } else {
195 mController = null;
196 }
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500197
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700198 ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
199 ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
Selim Cinek8081f092020-05-01 21:11:13 -0700200
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700201 mViewHolder.getPlayer().setBackgroundTintList(
Selim Cinekf0f74952020-04-21 11:45:16 -0700202 ColorStateList.valueOf(mBackgroundColor));
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500203
204 // Click action
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700205 PendingIntent clickIntent = data.getClickIntent();
206 if (clickIntent != null) {
Robert Snoebergereb49e942020-05-12 16:31:09 -0400207 mViewHolder.getPlayer().setOnClickListener(v -> {
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700208 mActivityStarter.postStartActivityDismissingKeyguard(clickIntent);
Beth Thibodeaua51c3142020-03-17 17:27:04 -0400209 });
210 }
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500211
Robert Snoebergereb49e942020-05-12 16:31:09 -0400212 ImageView albumView = mViewHolder.getAlbumView();
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400213 boolean hasArtwork = data.getArtwork() != null;
214 if (hasArtwork) {
Fabian Kozynski47714a92020-06-17 10:22:35 -0400215 Drawable artwork = scaleDrawable(data.getArtwork());
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400216 albumView.setImageDrawable(artwork);
217 }
218 setVisibleAndAlpha(collapsedSet, R.id.album_art, hasArtwork);
219 setVisibleAndAlpha(expandedSet, R.id.album_art, hasArtwork);
Selim Cinekf0f74952020-04-21 11:45:16 -0700220
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500221 // App icon
Robert Snoebergereb49e942020-05-12 16:31:09 -0400222 ImageView appIcon = mViewHolder.getAppIcon();
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400223 if (data.getAppIcon() != null) {
224 appIcon.setImageDrawable(data.getAppIcon());
225 } else {
226 Drawable iconDrawable = mContext.getDrawable(R.drawable.ic_music_note);
227 appIcon.setImageDrawable(iconDrawable);
228 }
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500229
Selim Cinekf0f74952020-04-21 11:45:16 -0700230 // Song name
Robert Snoebergereb49e942020-05-12 16:31:09 -0400231 TextView titleText = mViewHolder.getTitleText();
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700232 titleText.setText(data.getSong());
Selim Cinekf0f74952020-04-21 11:45:16 -0700233
234 // App title
Robert Snoebergereb49e942020-05-12 16:31:09 -0400235 TextView appName = mViewHolder.getAppName();
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700236 appName.setText(data.getApp());
Selim Cinekf0f74952020-04-21 11:45:16 -0700237
238 // Artist name
Robert Snoebergereb49e942020-05-12 16:31:09 -0400239 TextView artistText = mViewHolder.getArtistText();
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700240 artistText.setText(data.getArtist());
Selim Cinekf0f74952020-04-21 11:45:16 -0700241
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500242 // Transfer chip
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400243 mViewHolder.getSeamless().setVisibility(View.VISIBLE);
244 setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */);
245 setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */);
246 mViewHolder.getSeamless().setOnClickListener(v -> {
247 final Intent intent = new Intent()
248 .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
249 .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400250 data.getPackageName())
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400251 .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, mToken);
252 mActivityStarter.startActivity(intent, false, true /* dismissShade */,
253 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
254 });
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400255
256 ImageView iconView = mViewHolder.getSeamlessIcon();
257 TextView deviceName = mViewHolder.getSeamlessText();
258
Robert Snoeberger23e36892020-05-21 00:33:24 -0400259 final MediaDeviceData device = data.getDevice();
Robert Snoeberger07340432020-06-19 17:33:48 -0400260 final int seamlessId = mViewHolder.getSeamless().getId();
261 final int seamlessFallbackId = mViewHolder.getSeamlessFallback().getId();
262 final boolean showFallback = device != null && !device.getEnabled();
263 final int seamlessFallbackVisibility = showFallback ? View.VISIBLE : View.GONE;
264 mViewHolder.getSeamlessFallback().setVisibility(seamlessFallbackVisibility);
265 expandedSet.setVisibility(seamlessFallbackId, seamlessFallbackVisibility);
266 collapsedSet.setVisibility(seamlessFallbackId, seamlessFallbackVisibility);
267 final int seamlessVisibility = showFallback ? View.GONE : View.VISIBLE;
268 mViewHolder.getSeamless().setVisibility(seamlessVisibility);
269 expandedSet.setVisibility(seamlessId, seamlessVisibility);
270 collapsedSet.setVisibility(seamlessId, seamlessVisibility);
Robert Snoebergerf05aa68f2020-06-18 16:14:29 -0400271 final float seamlessAlpha = data.getResumption() ? DISABLED_ALPHA : 1.0f;
272 expandedSet.setAlpha(seamlessId, seamlessAlpha);
273 collapsedSet.setAlpha(seamlessId, seamlessAlpha);
274 // Disable clicking on output switcher for resumption controls.
275 mViewHolder.getSeamless().setEnabled(!data.getResumption());
Robert Snoeberger07340432020-06-19 17:33:48 -0400276 if (showFallback) {
277 iconView.setImageDrawable(null);
278 deviceName.setText(null);
Robert Snoeberger23e36892020-05-21 00:33:24 -0400279 } else if (device != null) {
Robert Snoeberger23e36892020-05-21 00:33:24 -0400280 Drawable icon = device.getIcon();
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400281 iconView.setVisibility(View.VISIBLE);
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400282 if (icon instanceof AdaptiveIcon) {
283 AdaptiveIcon aIcon = (AdaptiveIcon) icon;
284 aIcon.setBackgroundColor(mBackgroundColor);
285 iconView.setImageDrawable(aIcon);
286 } else {
287 iconView.setImageDrawable(icon);
288 }
Robert Snoeberger23e36892020-05-21 00:33:24 -0400289 deviceName.setText(device.getName());
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400290 } else {
291 // Reset to default
292 Log.w(TAG, "device is null. Not binding output chip.");
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400293 iconView.setVisibility(View.GONE);
294 deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
295 }
296
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700297 List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
298 // Media controls
299 int i = 0;
300 List<MediaAction> actionIcons = data.getActions();
301 for (; i < actionIcons.size() && i < ACTION_IDS.length; i++) {
Selim Cinekf0f74952020-04-21 11:45:16 -0700302 int actionId = ACTION_IDS[i];
Robert Snoebergereb49e942020-05-12 16:31:09 -0400303 final ImageButton button = mViewHolder.getAction(actionId);
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700304 MediaAction mediaAction = actionIcons.get(i);
305 button.setImageDrawable(mediaAction.getDrawable());
306 button.setContentDescription(mediaAction.getContentDescription());
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400307 Runnable action = mediaAction.getAction();
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700308
Beth Thibodeauf96f4fb2020-06-11 19:26:54 -0400309 if (action == null) {
310 button.setEnabled(false);
311 } else {
312 button.setEnabled(true);
313 button.setOnClickListener(v -> {
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400314 action.run();
Beth Thibodeauf96f4fb2020-06-11 19:26:54 -0400315 });
316 }
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700317 boolean visibleInCompat = actionsWhenCollapsed.contains(i);
Selim Cinek8081f092020-05-01 21:11:13 -0700318 setVisibleAndAlpha(collapsedSet, actionId, visibleInCompat);
319 setVisibleAndAlpha(expandedSet, actionId, true /*visible */);
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700320 }
321
322 // Hide any unused buttons
323 for (; i < ACTION_IDS.length; i++) {
Selim Cinek8081f092020-05-01 21:11:13 -0700324 setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /*visible */);
325 setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */);
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700326 }
327
328 // Seek Bar
Selim Cinekf418bb02020-05-04 17:16:58 -0700329 final MediaController controller = getController();
Lucas Dupin81e9beb2020-05-14 19:28:36 -0700330 mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700331
332 // Set up long press menu
333 // TODO: b/156036025 bring back media guts
334
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700335 // TODO: We don't need to refresh this state constantly, only if the state actually changed
336 // to something which might impact the measurement
337 mMediaViewController.refreshState();
Selim Cinekf0f74952020-04-21 11:45:16 -0700338 }
Beth Thibodeau23a33ab2020-04-07 20:51:57 -0400339
Selim Cinekf418bb02020-05-04 17:16:58 -0700340 @UiThread
Fabian Kozynski47714a92020-06-17 10:22:35 -0400341 private Drawable scaleDrawable(Icon icon) {
Selim Cinekc5436712020-04-27 15:15:44 -0700342 if (icon == null) {
343 return null;
344 }
345 // Let's scale down the View, such that the content always nicely fills the view.
346 // ThumbnailUtils actually scales it down such that it may not be filled for odd aspect
347 // ratios
348 Drawable drawable = icon.loadDrawable(mContext);
349 float aspectRatio = drawable.getIntrinsicHeight() / (float) drawable.getIntrinsicWidth();
350 Rect bounds;
351 if (aspectRatio > 1.0f) {
352 bounds = new Rect(0, 0, mAlbumArtSize, (int) (mAlbumArtSize * aspectRatio));
353 } else {
354 bounds = new Rect(0, 0, (int) (mAlbumArtSize / aspectRatio), mAlbumArtSize);
355 }
356 if (bounds.width() > mAlbumArtSize || bounds.height() > mAlbumArtSize) {
357 float offsetX = (bounds.width() - mAlbumArtSize) / 2.0f;
358 float offsetY = (bounds.height() - mAlbumArtSize) / 2.0f;
359 bounds.offset((int) -offsetX,(int) -offsetY);
360 }
361 drawable.setBounds(bounds);
Fabian Kozynski47714a92020-06-17 10:22:35 -0400362 return drawable;
Selim Cinekc5436712020-04-27 15:15:44 -0700363 }
364
Selim Cinekf0f74952020-04-21 11:45:16 -0700365 /**
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500366 * Get the current media controller
367 * @return the controller
368 */
369 public MediaController getController() {
370 return mController;
371 }
372
373 /**
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500374 * Check whether the media controlled by this player is currently playing
375 * @return whether it is playing, or false if no controller information
376 */
377 public boolean isPlaying() {
378 return isPlaying(mController);
379 }
380
381 /**
382 * Check whether the given controller is currently playing
383 * @param controller media controller to check
384 * @return whether it is playing, or false if no controller information
385 */
386 protected boolean isPlaying(MediaController controller) {
387 if (controller == null) {
388 return false;
389 }
390
391 PlaybackState state = controller.getPlaybackState();
392 if (state == null) {
393 return false;
394 }
395
396 return (state.getState() == PlaybackState.STATE_PLAYING);
397 }
398
Selim Cinek8081f092020-05-01 21:11:13 -0700399 private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible) {
400 set.setVisibility(actionId, visible? ConstraintSet.VISIBLE : ConstraintSet.GONE);
401 set.setAlpha(actionId, visible ? 1.0f : 0.0f);
402 }
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500403}