blob: d5c92f26e12b11f8c8acb051119d7adb1fb4394a [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;
Lucas Dupin81e9beb2020-05-14 19:28:36 -070023import android.graphics.Color;
Fabian Kozynski47714a92020-06-17 10:22:35 -040024import android.graphics.Outline;
Selim Cinekc5436712020-04-27 15:15:44 -070025import android.graphics.Rect;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050026import android.graphics.drawable.Drawable;
27import android.graphics.drawable.GradientDrawable;
Selim Cinekc5436712020-04-27 15:15:44 -070028import android.graphics.drawable.Icon;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050029import android.graphics.drawable.RippleDrawable;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050030import android.media.session.MediaController;
31import android.media.session.MediaSession;
32import android.media.session.PlaybackState;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050033import android.util.Log;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050034import android.view.View;
Fabian Kozynski47714a92020-06-17 10:22:35 -040035import android.view.ViewOutlineProvider;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050036import android.widget.ImageButton;
37import android.widget.ImageView;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050038import android.widget.TextView;
39
Selim Cinek2de5ebb2020-05-20 15:39:03 -070040import androidx.annotation.NonNull;
Robert Snoeberger9a7409b2020-04-09 18:12:27 -040041import androidx.annotation.Nullable;
Selim Cinekf418bb02020-05-04 17:16:58 -070042import androidx.annotation.UiThread;
Selim Cinek5dbef2d2020-05-07 17:44:38 -070043import androidx.constraintlayout.widget.ConstraintSet;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050044
Selim Cinekc5436712020-04-27 15:15:44 -070045import com.android.settingslib.Utils;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050046import com.android.settingslib.media.MediaOutputSliceConstants;
47import com.android.settingslib.widget.AdaptiveIcon;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050048import com.android.systemui.R;
Robert Snoeberger7cec5422020-05-29 17:09:14 -040049import com.android.systemui.dagger.qualifiers.Background;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050050import com.android.systemui.plugins.ActivityStarter;
Selim Cinek2de5ebb2020-05-20 15:39:03 -070051import com.android.systemui.util.animation.TransitionLayout;
Selim Cinek5dbef2d2020-05-07 17:44:38 -070052
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050053import java.util.List;
54import java.util.concurrent.Executor;
55
Robert Snoeberger7cec5422020-05-29 17:09:14 -040056import javax.inject.Inject;
57
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050058/**
Selim Cinekd8357922020-04-10 15:06:53 -070059 * A view controller used for Media Playback.
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050060 */
Robert Snoeberger3cc22222020-03-25 15:36:31 -040061public class MediaControlPanel {
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050062 private static final String TAG = "MediaControlPanel";
Selim Cinek5dbef2d2020-05-07 17:44:38 -070063
64 // Button IDs for QS controls
65 static final int[] ACTION_IDS = {
66 R.id.action0,
67 R.id.action1,
68 R.id.action2,
69 R.id.action3,
70 R.id.action4
71 };
72
73 private final SeekBarViewModel mSeekBarViewModel;
Robert Snoebergereb49e942020-05-12 16:31:09 -040074 private SeekBarObserver mSeekBarObserver;
Beth Thibodeau23a33ab2020-04-07 20:51:57 -040075 protected final Executor mBackgroundExecutor;
Beth Thibodeaue561c002020-04-23 17:33:00 -040076 private final ActivityStarter mActivityStarter;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050077
78 private Context mContext;
Robert Snoebergereb49e942020-05-12 16:31:09 -040079 private PlayerViewHolder mViewHolder;
Selim Cinek2de5ebb2020-05-20 15:39:03 -070080 private MediaViewController mMediaViewController;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050081 private MediaSession.Token mToken;
82 private MediaController mController;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050083 private int mBackgroundColor;
Selim Cinekc5436712020-04-27 15:15:44 -070084 private int mAlbumArtSize;
85 private int mAlbumArtRadius;
Fabian Kozynski47714a92020-06-17 10:22:35 -040086 // This will provide the corners for the album art.
87 private final ViewOutlineProvider mViewOutlineProvider;
Robert Snoeberger9a7409b2020-04-09 18:12:27 -040088
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050089 /**
90 * Initialize a new control panel
91 * @param context
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050092 * @param backgroundExecutor background executor, used for processing artwork
Beth Thibodeaue561c002020-04-23 17:33:00 -040093 * @param activityStarter activity starter
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050094 */
Robert Snoeberger7cec5422020-05-29 17:09:14 -040095 @Inject
96 public MediaControlPanel(Context context, @Background Executor backgroundExecutor,
Lucas Dupin84f5a0e2020-06-08 19:55:33 -070097 ActivityStarter activityStarter, MediaViewController mediaViewController,
Robert Snoeberger7cec5422020-05-29 17:09:14 -040098 SeekBarViewModel seekBarViewModel) {
Beth Thibodeau7b6c1782020-03-05 11:43:51 -050099 mContext = context;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500100 mBackgroundExecutor = backgroundExecutor;
Beth Thibodeaue561c002020-04-23 17:33:00 -0400101 mActivityStarter = activityStarter;
Robert Snoeberger7cec5422020-05-29 17:09:14 -0400102 mSeekBarViewModel = seekBarViewModel;
Lucas Dupin84f5a0e2020-06-08 19:55:33 -0700103 mMediaViewController = mediaViewController;
Selim Cinekc5436712020-04-27 15:15:44 -0700104 loadDimens();
Fabian Kozynski47714a92020-06-17 10:22:35 -0400105
106 mViewOutlineProvider = new ViewOutlineProvider() {
107 @Override
108 public void getOutline(View view, Outline outline) {
109 outline.setRoundRect(0, 0, mAlbumArtSize, mAlbumArtSize, mAlbumArtRadius);
110 }
111 };
Selim Cinekc5436712020-04-27 15:15:44 -0700112 }
113
Selim Cinek098baf42020-04-27 19:02:06 -0700114 public void onDestroy() {
Robert Snoebergereb49e942020-05-12 16:31:09 -0400115 if (mSeekBarObserver != null) {
116 mSeekBarViewModel.getProgress().removeObserver(mSeekBarObserver);
117 }
Robert Snoeberger734463e2020-05-20 02:10:56 -0400118 mSeekBarViewModel.onDestroy();
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700119 mMediaViewController.onDestroy();
Selim Cinek098baf42020-04-27 19:02:06 -0700120 }
121
Selim Cinekc5436712020-04-27 15:15:44 -0700122 private void loadDimens() {
123 mAlbumArtRadius = mContext.getResources().getDimensionPixelSize(
124 Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
125 mAlbumArtSize = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_album_size);
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500126 }
127
128 /**
Robert Snoebergereb49e942020-05-12 16:31:09 -0400129 * Get the view holder used to display media controls
130 * @return the view holder
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500131 */
Robert Snoebergereb49e942020-05-12 16:31:09 -0400132 @Nullable
133 public PlayerViewHolder getView() {
134 return mViewHolder;
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500135 }
136
137 /**
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700138 * Get the view controller used to display media controls
139 * @return the media view controller
140 */
141 @NonNull
142 public MediaViewController getMediaViewController() {
143 return mMediaViewController;
144 }
145
146 /**
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700147 * Sets the listening state of the player.
148 *
149 * Should be set to true when the QS panel is open. Otherwise, false. This is a signal to avoid
150 * unnecessary work when the QS panel is closed.
151 *
152 * @param listening True when player should be active. Otherwise, false.
153 */
154 public void setListening(boolean listening) {
155 mSeekBarViewModel.setListening(listening);
156 }
157
158 /**
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500159 * Get the context
160 * @return context
161 */
162 public Context getContext() {
163 return mContext;
164 }
165
Robert Snoebergereb49e942020-05-12 16:31:09 -0400166 /** Attaches the player to the view holder. */
167 public void attach(PlayerViewHolder vh) {
168 mViewHolder = vh;
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700169 TransitionLayout player = vh.getPlayer();
Fabian Kozynski47714a92020-06-17 10:22:35 -0400170
171 ImageView albumView = vh.getAlbumView();
172 albumView.setOutlineProvider(mViewOutlineProvider);
173 albumView.setClipToOutline(true);
174
Robert Snoeberger45be3fb2020-05-19 02:00:43 -0400175 mSeekBarObserver = new SeekBarObserver(vh);
Robert Snoebergereb49e942020-05-12 16:31:09 -0400176 mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
Robert Snoeberger77d3dca2020-06-02 17:36:49 -0400177 mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700178 mMediaViewController.attach(player);
Robert Snoebergereb49e942020-05-12 16:31:09 -0400179 }
180
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500181 /**
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700182 * Bind this view based on the data given
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500183 */
Fabian Kozynski47714a92020-06-17 10:22:35 -0400184 public void bind(@NonNull MediaData data) {
Robert Snoebergereb49e942020-05-12 16:31:09 -0400185 if (mViewHolder == null) {
186 return;
187 }
Selim Cinekf0f74952020-04-21 11:45:16 -0700188 MediaSession.Token token = data.getToken();
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700189 mBackgroundColor = data.getBackgroundColor();
Beth Thibodeau23a33ab2020-04-07 20:51:57 -0400190 if (mToken == null || !mToken.equals(token)) {
191 mToken = token;
Beth Thibodeau23a33ab2020-04-07 20:51:57 -0400192 }
193
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400194 if (mToken != null) {
195 mController = new MediaController(mContext, mToken);
196 } else {
197 mController = null;
198 }
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500199
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700200 ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
201 ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
Selim Cinek8081f092020-05-01 21:11:13 -0700202
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700203 mViewHolder.getPlayer().setBackgroundTintList(
Selim Cinekf0f74952020-04-21 11:45:16 -0700204 ColorStateList.valueOf(mBackgroundColor));
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500205
206 // Click action
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700207 PendingIntent clickIntent = data.getClickIntent();
208 if (clickIntent != null) {
Robert Snoebergereb49e942020-05-12 16:31:09 -0400209 mViewHolder.getPlayer().setOnClickListener(v -> {
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700210 mActivityStarter.postStartActivityDismissingKeyguard(clickIntent);
Beth Thibodeaua51c3142020-03-17 17:27:04 -0400211 });
212 }
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500213
Robert Snoebergereb49e942020-05-12 16:31:09 -0400214 ImageView albumView = mViewHolder.getAlbumView();
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400215 boolean hasArtwork = data.getArtwork() != null;
216 if (hasArtwork) {
Fabian Kozynski47714a92020-06-17 10:22:35 -0400217 Drawable artwork = scaleDrawable(data.getArtwork());
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400218 albumView.setImageDrawable(artwork);
219 }
220 setVisibleAndAlpha(collapsedSet, R.id.album_art, hasArtwork);
221 setVisibleAndAlpha(expandedSet, R.id.album_art, hasArtwork);
Selim Cinekf0f74952020-04-21 11:45:16 -0700222
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500223 // App icon
Robert Snoebergereb49e942020-05-12 16:31:09 -0400224 ImageView appIcon = mViewHolder.getAppIcon();
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400225 if (data.getAppIcon() != null) {
226 appIcon.setImageDrawable(data.getAppIcon());
227 } else {
228 Drawable iconDrawable = mContext.getDrawable(R.drawable.ic_music_note);
229 appIcon.setImageDrawable(iconDrawable);
230 }
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500231
Selim Cinekf0f74952020-04-21 11:45:16 -0700232 // Song name
Robert Snoebergereb49e942020-05-12 16:31:09 -0400233 TextView titleText = mViewHolder.getTitleText();
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700234 titleText.setText(data.getSong());
Selim Cinekf0f74952020-04-21 11:45:16 -0700235
236 // App title
Robert Snoebergereb49e942020-05-12 16:31:09 -0400237 TextView appName = mViewHolder.getAppName();
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700238 appName.setText(data.getApp());
Selim Cinekf0f74952020-04-21 11:45:16 -0700239
240 // Artist name
Robert Snoebergereb49e942020-05-12 16:31:09 -0400241 TextView artistText = mViewHolder.getArtistText();
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700242 artistText.setText(data.getArtist());
Selim Cinekf0f74952020-04-21 11:45:16 -0700243
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500244 // Transfer chip
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400245 mViewHolder.getSeamless().setVisibility(View.VISIBLE);
246 setVisibleAndAlpha(collapsedSet, R.id.media_seamless, true /*visible */);
247 setVisibleAndAlpha(expandedSet, R.id.media_seamless, true /*visible */);
248 mViewHolder.getSeamless().setOnClickListener(v -> {
249 final Intent intent = new Intent()
250 .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
251 .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400252 data.getPackageName())
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400253 .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN, mToken);
254 mActivityStarter.startActivity(intent, false, true /* dismissShade */,
255 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
256 });
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400257
258 ImageView iconView = mViewHolder.getSeamlessIcon();
259 TextView deviceName = mViewHolder.getSeamlessText();
260
261 // Update the outline color
Lucas Dupin5feeaca2020-05-28 11:01:54 -0700262 RippleDrawable bkgDrawable = (RippleDrawable) mViewHolder.getSeamless().getForeground();
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400263 GradientDrawable rect = (GradientDrawable) bkgDrawable.getDrawable(0);
264 rect.setStroke(2, deviceName.getCurrentTextColor());
265 rect.setColor(Color.TRANSPARENT);
266
Robert Snoeberger23e36892020-05-21 00:33:24 -0400267 final MediaDeviceData device = data.getDevice();
Selim Cinekeb70e132020-06-12 19:04:42 -0700268 int seamlessId = mViewHolder.getSeamless().getId();
Robert Snoeberger23e36892020-05-21 00:33:24 -0400269 if (device != null && !device.getEnabled()) {
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400270 mViewHolder.getSeamless().setEnabled(false);
Selim Cinekeb70e132020-06-12 19:04:42 -0700271 expandedSet.setAlpha(seamlessId, 0.38f);
272 collapsedSet.setAlpha(seamlessId, 0.38f);
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400273 iconView.setImageResource(R.drawable.ic_hardware_speaker);
274 iconView.setVisibility(View.VISIBLE);
275 deviceName.setText(R.string.media_seamless_remote_device);
Robert Snoeberger23e36892020-05-21 00:33:24 -0400276 } else if (device != null) {
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400277 mViewHolder.getSeamless().setEnabled(true);
Selim Cinekeb70e132020-06-12 19:04:42 -0700278 expandedSet.setAlpha(seamlessId, 1.0f);
279 collapsedSet.setAlpha(seamlessId, 1.0f);
Robert Snoeberger23e36892020-05-21 00:33:24 -0400280 Drawable icon = device.getIcon();
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400281 iconView.setVisibility(View.VISIBLE);
282
283 if (icon instanceof AdaptiveIcon) {
284 AdaptiveIcon aIcon = (AdaptiveIcon) icon;
285 aIcon.setBackgroundColor(mBackgroundColor);
286 iconView.setImageDrawable(aIcon);
287 } else {
288 iconView.setImageDrawable(icon);
289 }
Robert Snoeberger23e36892020-05-21 00:33:24 -0400290 deviceName.setText(device.getName());
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400291 } else {
292 // Reset to default
293 Log.w(TAG, "device is null. Not binding output chip.");
294 mViewHolder.getSeamless().setEnabled(true);
Selim Cinekeb70e132020-06-12 19:04:42 -0700295 expandedSet.setAlpha(seamlessId, 1.0f);
296 collapsedSet.setAlpha(seamlessId, 1.0f);
Robert Snoeberger70d0d6b2020-05-14 16:47:02 -0400297 iconView.setVisibility(View.GONE);
298 deviceName.setText(com.android.internal.R.string.ext_media_seamless_action);
299 }
300
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700301 List<Integer> actionsWhenCollapsed = data.getActionsToShowInCompact();
302 // Media controls
303 int i = 0;
304 List<MediaAction> actionIcons = data.getActions();
305 for (; i < actionIcons.size() && i < ACTION_IDS.length; i++) {
Selim Cinekf0f74952020-04-21 11:45:16 -0700306 int actionId = ACTION_IDS[i];
Robert Snoebergereb49e942020-05-12 16:31:09 -0400307 final ImageButton button = mViewHolder.getAction(actionId);
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700308 MediaAction mediaAction = actionIcons.get(i);
309 button.setImageDrawable(mediaAction.getDrawable());
310 button.setContentDescription(mediaAction.getContentDescription());
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400311 Runnable action = mediaAction.getAction();
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700312
Beth Thibodeauf96f4fb2020-06-11 19:26:54 -0400313 if (action == null) {
314 button.setEnabled(false);
315 } else {
316 button.setEnabled(true);
317 button.setOnClickListener(v -> {
Beth Thibodeauf55bc6a2020-05-20 02:01:31 -0400318 action.run();
Beth Thibodeauf96f4fb2020-06-11 19:26:54 -0400319 });
320 }
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700321 boolean visibleInCompat = actionsWhenCollapsed.contains(i);
Selim Cinek8081f092020-05-01 21:11:13 -0700322 setVisibleAndAlpha(collapsedSet, actionId, visibleInCompat);
323 setVisibleAndAlpha(expandedSet, actionId, true /*visible */);
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700324 }
325
326 // Hide any unused buttons
327 for (; i < ACTION_IDS.length; i++) {
Selim Cinek8081f092020-05-01 21:11:13 -0700328 setVisibleAndAlpha(expandedSet, ACTION_IDS[i], false /*visible */);
329 setVisibleAndAlpha(collapsedSet, ACTION_IDS[i], false /*visible */);
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700330 }
331
332 // Seek Bar
Selim Cinekf418bb02020-05-04 17:16:58 -0700333 final MediaController controller = getController();
Lucas Dupin81e9beb2020-05-14 19:28:36 -0700334 mBackgroundExecutor.execute(() -> mSeekBarViewModel.updateController(controller));
Selim Cinek5dbef2d2020-05-07 17:44:38 -0700335
336 // Set up long press menu
337 // TODO: b/156036025 bring back media guts
338
Selim Cinek2de5ebb2020-05-20 15:39:03 -0700339 // TODO: We don't need to refresh this state constantly, only if the state actually changed
340 // to something which might impact the measurement
341 mMediaViewController.refreshState();
Selim Cinekf0f74952020-04-21 11:45:16 -0700342 }
Beth Thibodeau23a33ab2020-04-07 20:51:57 -0400343
Selim Cinekf418bb02020-05-04 17:16:58 -0700344 @UiThread
Fabian Kozynski47714a92020-06-17 10:22:35 -0400345 private Drawable scaleDrawable(Icon icon) {
Selim Cinekc5436712020-04-27 15:15:44 -0700346 if (icon == null) {
347 return null;
348 }
349 // Let's scale down the View, such that the content always nicely fills the view.
350 // ThumbnailUtils actually scales it down such that it may not be filled for odd aspect
351 // ratios
352 Drawable drawable = icon.loadDrawable(mContext);
353 float aspectRatio = drawable.getIntrinsicHeight() / (float) drawable.getIntrinsicWidth();
354 Rect bounds;
355 if (aspectRatio > 1.0f) {
356 bounds = new Rect(0, 0, mAlbumArtSize, (int) (mAlbumArtSize * aspectRatio));
357 } else {
358 bounds = new Rect(0, 0, (int) (mAlbumArtSize / aspectRatio), mAlbumArtSize);
359 }
360 if (bounds.width() > mAlbumArtSize || bounds.height() > mAlbumArtSize) {
361 float offsetX = (bounds.width() - mAlbumArtSize) / 2.0f;
362 float offsetY = (bounds.height() - mAlbumArtSize) / 2.0f;
363 bounds.offset((int) -offsetX,(int) -offsetY);
364 }
365 drawable.setBounds(bounds);
Fabian Kozynski47714a92020-06-17 10:22:35 -0400366 return drawable;
Selim Cinekc5436712020-04-27 15:15:44 -0700367 }
368
Selim Cinekf0f74952020-04-21 11:45:16 -0700369 /**
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500370 * Get the current media controller
371 * @return the controller
372 */
373 public MediaController getController() {
374 return mController;
375 }
376
377 /**
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500378 * Check whether the media controlled by this player is currently playing
379 * @return whether it is playing, or false if no controller information
380 */
381 public boolean isPlaying() {
382 return isPlaying(mController);
383 }
384
385 /**
386 * Check whether the given controller is currently playing
387 * @param controller media controller to check
388 * @return whether it is playing, or false if no controller information
389 */
390 protected boolean isPlaying(MediaController controller) {
391 if (controller == null) {
392 return false;
393 }
394
395 PlaybackState state = controller.getPlaybackState();
396 if (state == null) {
397 return false;
398 }
399
400 return (state.getState() == PlaybackState.STATE_PLAYING);
401 }
402
Selim Cinek8081f092020-05-01 21:11:13 -0700403 private void setVisibleAndAlpha(ConstraintSet set, int actionId, boolean visible) {
404 set.setVisibility(actionId, visible? ConstraintSet.VISIBLE : ConstraintSet.GONE);
405 set.setAlpha(actionId, visible ? 1.0f : 0.0f);
406 }
Beth Thibodeau7b6c1782020-03-05 11:43:51 -0500407}