130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownpackage com.android.car.media; 230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport android.annotation.NonNull; 430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport android.annotation.Nullable; 5035185163a5eba95b7655439bff9e162494f25ffRoberto Perezimport android.media.session.PlaybackState; 6035185163a5eba95b7655439bff9e162494f25ffRoberto Perezimport android.support.v4.media.session.PlaybackStateCompat; 730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport android.view.View; 830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport android.widget.ImageView; 930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport android.widget.SeekBar; 1030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport android.widget.TextView; 1130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 1230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport com.android.car.media.common.MediaItemMetadata; 1330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport com.android.car.media.common.PlaybackModel; 1430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 1530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport java.text.DateFormat; 1630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport java.text.SimpleDateFormat; 1730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport java.util.Date; 1830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownimport java.util.Locale; 1930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 2030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown/** 2130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * Common controller for displaying current track's metadata. 2230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown */ 2330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brownpublic class MetadataController { 2430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 2530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private static final DateFormat TIME_FORMAT = new SimpleDateFormat("m:ss", Locale.US); 2630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 2730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown @NonNull 2830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private final TextView mTitle; 2930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown @NonNull 3030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private final TextView mSubtitle; 3130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown @Nullable 3230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private final TextView mTime; 3330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown @NonNull 3430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private final SeekBar mSeekBar; 3530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown @Nullable 3630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private final ImageView mAlbumArt; 3730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 3830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown @Nullable 3930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private PlaybackModel mModel; 4030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 41839543fa68e92663908eb074b65c74e801168aedJoshua Brown private boolean mUpdatesPaused; 42839543fa68e92663908eb074b65c74e801168aedJoshua Brown private boolean mNeedsMetadataUpdate; 43a51d23d9109f44187200495fdb4523d47255b14aRoberto Perez private int mAlbumArtSize; 44839543fa68e92663908eb074b65c74e801168aedJoshua Brown 4530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private final PlaybackModel.PlaybackObserver mPlaybackObserver = 4630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown new PlaybackModel.PlaybackObserver() { 4730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown @Override 4830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown public void onPlaybackStateChanged() { 4930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown updateState(); 5030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 5130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 5230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown @Override 5330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown public void onSourceChanged() { 5430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown updateState(); 5530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown updateMetadata(); 5630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 5730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 5830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown @Override 5930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown public void onMetadataChanged() { 6030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown updateMetadata(); 6130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 6230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown }; 6330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 6430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown /** 6530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * Create a new MetadataController that operates on the provided Views 6630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * @param title Displays the track's title. Must not be {@code null}. 6730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * @param subtitle Displays the track's artist. Must not be {@code null}. 6830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * @param time Displays the track's progress as text. May be {@code null}. 6930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * @param seekBar Displays the track's progress visually. Must not be {@code null}. 7030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * @param albumArt Displays the track's album art. May be {@code null}. 7130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown */ 7230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown public MetadataController(@NonNull TextView title, @NonNull TextView subtitle, 7330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown @Nullable TextView time, @NonNull SeekBar seekBar, @Nullable ImageView albumArt) { 7430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mTitle = title; 7530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mSubtitle = subtitle; 7630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mTime = time; 7730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mSeekBar = seekBar; 78a51d23d9109f44187200495fdb4523d47255b14aRoberto Perez mSeekBar.setOnTouchListener((view, event) -> true); 7930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mAlbumArt = albumArt; 80a51d23d9109f44187200495fdb4523d47255b14aRoberto Perez mAlbumArtSize = title.getContext().getResources() 81a51d23d9109f44187200495fdb4523d47255b14aRoberto Perez .getDimensionPixelSize(R.dimen.playback_album_art_size_large); 8230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 8330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 8430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown /** 8530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * Registers the {@link PlaybackModel} this widget will use to follow playback state. 8630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * Consumers of this class must unregister the {@link PlaybackModel} by calling this method with 8730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * null. 8830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * 8930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown * @param model {@link PlaybackModel} to subscribe, or null to unsubscribe. 9030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown */ 9130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown public void setModel(@Nullable PlaybackModel model) { 9230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown if (mModel != null) { 9330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mModel.unregisterObserver(mPlaybackObserver); 9430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 9530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mModel = model; 9630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown if (mModel != null) { 9730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mModel.registerObserver(mPlaybackObserver); 9830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 9930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 10030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 10130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private void updateState() { 10230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown updateProgress(); 10330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 104839543fa68e92663908eb074b65c74e801168aedJoshua Brown mSeekBar.removeCallbacks(mSeekBarRunnable); 10530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown if (mModel != null && mModel.isPlaying()) { 10630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mSeekBar.post(mSeekBarRunnable); 10730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 10830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 10930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 11030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private void updateMetadata() { 111839543fa68e92663908eb074b65c74e801168aedJoshua Brown if(mUpdatesPaused) { 112839543fa68e92663908eb074b65c74e801168aedJoshua Brown mNeedsMetadataUpdate = true; 113839543fa68e92663908eb074b65c74e801168aedJoshua Brown return; 114839543fa68e92663908eb074b65c74e801168aedJoshua Brown } 115839543fa68e92663908eb074b65c74e801168aedJoshua Brown 116839543fa68e92663908eb074b65c74e801168aedJoshua Brown mNeedsMetadataUpdate = false; 11730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown MediaItemMetadata metadata = mModel != null ? mModel.getMetadata() : null; 11830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mTitle.setText(metadata != null ? metadata.getTitle() : null); 11930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mSubtitle.setText(metadata != null ? metadata.getSubtitle() : null); 1201d3e7e02676ed495b9f99701fa4647aa524d3f1bRoberto Perez if (mAlbumArt != null && metadata != null && (metadata.getAlbumArtUri() != null 1211d3e7e02676ed495b9f99701fa4647aa524d3f1bRoberto Perez || metadata.getAlbumArtBitmap() != null)) { 1221d3e7e02676ed495b9f99701fa4647aa524d3f1bRoberto Perez mAlbumArt.setVisibility(View.VISIBLE); 123a51d23d9109f44187200495fdb4523d47255b14aRoberto Perez metadata.getAlbumArt(mAlbumArt.getContext(), mAlbumArtSize, mAlbumArtSize, true) 124a51d23d9109f44187200495fdb4523d47255b14aRoberto Perez .thenAccept(mAlbumArt::setImageBitmap); 1251d3e7e02676ed495b9f99701fa4647aa524d3f1bRoberto Perez } else if (mAlbumArt != null) { 1261d3e7e02676ed495b9f99701fa4647aa524d3f1bRoberto Perez mAlbumArt.setVisibility(View.GONE); 12730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 12830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 12930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 13030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private static final long SEEK_BAR_UPDATE_TIME_INTERVAL_MS = 1000; 13130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 13230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private final Runnable mSeekBarRunnable = new Runnable() { 13330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown @Override 13430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown public void run() { 13530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown if (mModel == null || !mModel.isPlaying()) { 13630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown return; 13730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 13830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown updateProgress(); 13930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mSeekBar.postDelayed(this, SEEK_BAR_UPDATE_TIME_INTERVAL_MS); 14030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 14130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 14230ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown }; 14330ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 14430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown private void updateProgress() { 14530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown if (mModel == null) { 14630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mTime.setVisibility(View.INVISIBLE); 14730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mSeekBar.setVisibility(View.INVISIBLE); 14830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown return; 14930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 15030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown long maxProgress = mModel.getMaxProgress(); 151035185163a5eba95b7655439bff9e162494f25ffRoberto Perez long progress = mModel.getProgress(); 152035185163a5eba95b7655439bff9e162494f25ffRoberto Perez int visibility = maxProgress > 0 && progress != PlaybackState.PLAYBACK_POSITION_UNKNOWN 153035185163a5eba95b7655439bff9e162494f25ffRoberto Perez ? View.VISIBLE : View.INVISIBLE; 15430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown if (mTime != null) { 15530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown String time = String.format("%s / %s", 156035185163a5eba95b7655439bff9e162494f25ffRoberto Perez TIME_FORMAT.format(new Date(progress)), 15730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown TIME_FORMAT.format(new Date(maxProgress))); 15830ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mTime.setVisibility(visibility); 15930ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mTime.setText(time); 16030ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 16130ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown mSeekBar.setVisibility(visibility); 162035185163a5eba95b7655439bff9e162494f25ffRoberto Perez mSeekBar.setMax((int) maxProgress); 163035185163a5eba95b7655439bff9e162494f25ffRoberto Perez mSeekBar.setProgress((int) progress); 16430ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown } 16530ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 16630ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown 167839543fa68e92663908eb074b65c74e801168aedJoshua Brown public void pauseUpdates() { 168839543fa68e92663908eb074b65c74e801168aedJoshua Brown mUpdatesPaused = true; 169839543fa68e92663908eb074b65c74e801168aedJoshua Brown } 170839543fa68e92663908eb074b65c74e801168aedJoshua Brown 171839543fa68e92663908eb074b65c74e801168aedJoshua Brown public void resumeUpdates() { 172839543fa68e92663908eb074b65c74e801168aedJoshua Brown mUpdatesPaused = false; 173839543fa68e92663908eb074b65c74e801168aedJoshua Brown if (mNeedsMetadataUpdate) { 174839543fa68e92663908eb074b65c74e801168aedJoshua Brown updateMetadata(); 175839543fa68e92663908eb074b65c74e801168aedJoshua Brown } 176839543fa68e92663908eb074b65c74e801168aedJoshua Brown } 17730ff1007ab6729566d053649d3e973ac9fd33627Joshua Brown} 178