/* * Copyright (C) 2016 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 android.support.v17.leanback.media; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.session.MediaControllerCompat; import android.support.v4.media.session.PlaybackStateCompat; import android.util.Log; /** * A helper class for implementing a glue layer for {@link MediaControllerCompat}. */ public abstract class MediaControllerGlue extends PlaybackControlGlue { static final String TAG = "MediaControllerGlue"; static final boolean DEBUG = false; MediaControllerCompat mMediaController; private final MediaControllerCompat.Callback mCallback = new MediaControllerCompat.Callback() { @Override public void onMetadataChanged(MediaMetadataCompat metadata) { if (DEBUG) Log.v(TAG, "onMetadataChanged"); MediaControllerGlue.this.onMetadataChanged(); } @Override public void onPlaybackStateChanged(PlaybackStateCompat state) { if (DEBUG) Log.v(TAG, "onPlaybackStateChanged"); onStateChanged(); } @Override public void onSessionDestroyed() { if (DEBUG) Log.v(TAG, "onSessionDestroyed"); mMediaController = null; } @Override public void onSessionEvent(String event, Bundle extras) { if (DEBUG) Log.v(TAG, "onSessionEvent"); } }; /** * Constructor for the glue. * * @param context * @param fastForwardSpeeds Array of seek speeds for fast forward. * @param rewindSpeeds Array of seek speeds for rewind. */ public MediaControllerGlue(Context context, int[] fastForwardSpeeds, int[] rewindSpeeds) { super(context, fastForwardSpeeds, rewindSpeeds); } /** * Attaches to the given media controller. */ public void attachToMediaController(MediaControllerCompat mediaController) { if (mediaController != mMediaController) { if (DEBUG) Log.v(TAG, "New media controller " + mediaController); detach(); mMediaController = mediaController; if (mMediaController != null) { mMediaController.registerCallback(mCallback); } onMetadataChanged(); onStateChanged(); } } /** * Detaches from the media controller. Must be called when the object is no longer * needed. */ public void detach() { if (mMediaController != null) { mMediaController.unregisterCallback(mCallback); } mMediaController = null; } /** * Returns the media controller currently attached. */ public final MediaControllerCompat getMediaController() { return mMediaController; } @Override public boolean hasValidMedia() { return mMediaController != null && mMediaController.getMetadata() != null; } @Override public boolean isMediaPlaying() { return mMediaController.getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING; } @Override public int getCurrentSpeedId() { int speed = (int) mMediaController.getPlaybackState().getPlaybackSpeed(); if (speed == 0) { return PLAYBACK_SPEED_PAUSED; } else if (speed == 1) { return PLAYBACK_SPEED_NORMAL; } else if (speed > 0) { int[] seekSpeeds = getFastForwardSpeeds(); for (int index = 0; index < seekSpeeds.length; index++) { if (speed == seekSpeeds[index]) { return PLAYBACK_SPEED_FAST_L0 + index; } } } else { int[] seekSpeeds = getRewindSpeeds(); for (int index = 0; index < seekSpeeds.length; index++) { if (-speed == seekSpeeds[index]) { return -PLAYBACK_SPEED_FAST_L0 - index; } } } Log.w(TAG, "Couldn't find index for speed " + speed); return PLAYBACK_SPEED_INVALID; } @Override public CharSequence getMediaTitle() { return mMediaController.getMetadata().getDescription().getTitle(); } @Override public CharSequence getMediaSubtitle() { return mMediaController.getMetadata().getDescription().getSubtitle(); } @Override public int getMediaDuration() { return (int) mMediaController.getMetadata().getLong( MediaMetadataCompat.METADATA_KEY_DURATION); } @Override public int getCurrentPosition() { return (int) mMediaController.getPlaybackState().getPosition(); } @Override public Drawable getMediaArt() { Bitmap bitmap = mMediaController.getMetadata().getDescription().getIconBitmap(); return bitmap == null ? null : new BitmapDrawable(getContext().getResources(), bitmap); } @Override public long getSupportedActions() { long result = 0; long actions = mMediaController.getPlaybackState().getActions(); if ((actions & PlaybackStateCompat.ACTION_PLAY_PAUSE) != 0) { result |= ACTION_PLAY_PAUSE; } if ((actions & PlaybackStateCompat.ACTION_SKIP_TO_NEXT) != 0) { result |= ACTION_SKIP_TO_NEXT; } if ((actions & PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS) != 0) { result |= ACTION_SKIP_TO_PREVIOUS; } if ((actions & PlaybackStateCompat.ACTION_FAST_FORWARD) != 0) { result |= ACTION_FAST_FORWARD; } if ((actions & PlaybackStateCompat.ACTION_REWIND) != 0) { result |= ACTION_REWIND; } return result; } @Override public void play(int speed) { if (DEBUG) Log.v(TAG, "startPlayback speed " + speed); if (speed == PLAYBACK_SPEED_NORMAL) { mMediaController.getTransportControls().play(); } else if (speed > 0) { mMediaController.getTransportControls().fastForward(); } else { mMediaController.getTransportControls().rewind(); } } @Override public void pause() { if (DEBUG) Log.v(TAG, "pausePlayback"); mMediaController.getTransportControls().pause(); } @Override public void next() { if (DEBUG) Log.v(TAG, "skipToNext"); mMediaController.getTransportControls().skipToNext(); } @Override public void previous() { if (DEBUG) Log.v(TAG, "skipToPrevious"); mMediaController.getTransportControls().skipToPrevious(); } }