1 package android.support.v17.leanback.app; 2 3 import android.content.Context; 4 import android.graphics.Bitmap; 5 import android.graphics.drawable.BitmapDrawable; 6 import android.graphics.drawable.Drawable; 7 import android.os.Bundle; 8 import android.support.v4.media.MediaMetadataCompat; 9 import android.support.v4.media.session.MediaControllerCompat; 10 import android.support.v4.media.session.PlaybackStateCompat; 11 import android.util.Log; 12 13 /** 14 * A helper class for implementing a glue layer between a 15 * {@link PlaybackOverlayFragment} and a 16 * {@link android.support.v4.media.session.MediaControllerCompat}. 17 */ 18 public abstract class MediaControllerGlue extends PlaybackControlGlue { 19 private static final String TAG = "MediaControllerGlue"; 20 private static final boolean DEBUG = false; 21 22 private MediaControllerCompat mMediaController; 23 24 private final MediaControllerCompat.Callback mCallback = new MediaControllerCompat.Callback() { 25 @Override 26 public void onMetadataChanged(MediaMetadataCompat metadata) { 27 if (DEBUG) Log.v(TAG, "onMetadataChanged"); 28 MediaControllerGlue.this.onMetadataChanged(); 29 } 30 @Override 31 public void onPlaybackStateChanged(PlaybackStateCompat state) { 32 if (DEBUG) Log.v(TAG, "onPlaybackStateChanged"); 33 onStateChanged(); 34 } 35 @Override 36 public void onSessionDestroyed() { 37 if (DEBUG) Log.v(TAG, "onSessionDestroyed"); 38 mMediaController = null; 39 } 40 @Override 41 public void onSessionEvent(String event, Bundle extras) { 42 if (DEBUG) Log.v(TAG, "onSessionEvent"); 43 } 44 }; 45 46 /** 47 * Constructor for the glue. 48 * 49 * <p>The {@link PlaybackOverlayFragment} must be passed in. 50 * A {@link android.support.v17.leanback.widget.OnItemViewClickedListener} and 51 * {@link PlaybackOverlayFragment.InputEventHandler} 52 * will be set on the fragment. 53 * </p> 54 * 55 * @param context 56 * @param fragment 57 * @param seekSpeeds Array of seek speeds for fast forward and rewind. 58 */ MediaControllerGlue(Context context, PlaybackOverlayFragment fragment, int[] seekSpeeds)59 public MediaControllerGlue(Context context, 60 PlaybackOverlayFragment fragment, 61 int[] seekSpeeds) { 62 super(context, fragment, seekSpeeds); 63 } 64 65 /** 66 * Constructor for the glue. 67 * 68 * <p>The {@link PlaybackOverlayFragment} must be passed in. 69 * A {@link android.support.v17.leanback.widget.OnItemViewClickedListener} and 70 * {@link PlaybackOverlayFragment.InputEventHandler} 71 * will be set on the fragment. 72 * </p> 73 * 74 * @param context 75 * @param fragment 76 * @param fastForwardSpeeds Array of seek speeds for fast forward. 77 * @param rewindSpeeds Array of seek speeds for rewind. 78 */ MediaControllerGlue(Context context, PlaybackOverlayFragment fragment, int[] fastForwardSpeeds, int[] rewindSpeeds)79 public MediaControllerGlue(Context context, 80 PlaybackOverlayFragment fragment, 81 int[] fastForwardSpeeds, 82 int[] rewindSpeeds) { 83 super(context, fragment, fastForwardSpeeds, rewindSpeeds); 84 } 85 86 /** 87 * Attaches to the given media controller. 88 */ attachToMediaController(MediaControllerCompat mediaController)89 public void attachToMediaController(MediaControllerCompat mediaController) { 90 if (mediaController != mMediaController) { 91 if (DEBUG) Log.v(TAG, "New media controller " + mediaController); 92 detach(); 93 mMediaController = mediaController; 94 if (mMediaController != null) { 95 mMediaController.registerCallback(mCallback); 96 } 97 onMetadataChanged(); 98 onStateChanged(); 99 } 100 } 101 102 /** 103 * Detaches from the media controller. Must be called when the object is no longer 104 * needed. 105 */ detach()106 public void detach() { 107 if (mMediaController != null) { 108 mMediaController.unregisterCallback(mCallback); 109 } 110 mMediaController = null; 111 } 112 113 /** 114 * Returns the media controller currently attached. 115 */ getMediaController()116 public final MediaControllerCompat getMediaController() { 117 return mMediaController; 118 } 119 120 @Override hasValidMedia()121 public boolean hasValidMedia() { 122 return mMediaController != null && mMediaController.getMetadata() != null; 123 } 124 125 @Override isMediaPlaying()126 public boolean isMediaPlaying() { 127 return mMediaController.getPlaybackState().getState() == PlaybackStateCompat.STATE_PLAYING; 128 } 129 130 @Override getCurrentSpeedId()131 public int getCurrentSpeedId() { 132 int speed = (int) mMediaController.getPlaybackState().getPlaybackSpeed(); 133 if (speed == 0) { 134 return PLAYBACK_SPEED_PAUSED; 135 } else if (speed == 1) { 136 return PLAYBACK_SPEED_NORMAL; 137 } else if (speed > 0) { 138 int[] seekSpeeds = getFastForwardSpeeds(); 139 for (int index = 0; index < seekSpeeds.length; index++) { 140 if (speed == seekSpeeds[index]) { 141 return PLAYBACK_SPEED_FAST_L0 + index; 142 } 143 } 144 } else { 145 int[] seekSpeeds = getRewindSpeeds(); 146 for (int index = 0; index < seekSpeeds.length; index++) { 147 if (-speed == seekSpeeds[index]) { 148 return -PLAYBACK_SPEED_FAST_L0 - index; 149 } 150 } 151 } 152 Log.w(TAG, "Couldn't find index for speed " + speed); 153 return PLAYBACK_SPEED_INVALID; 154 } 155 156 @Override getMediaTitle()157 public CharSequence getMediaTitle() { 158 return mMediaController.getMetadata().getDescription().getTitle(); 159 } 160 161 @Override getMediaSubtitle()162 public CharSequence getMediaSubtitle() { 163 return mMediaController.getMetadata().getDescription().getSubtitle(); 164 } 165 166 @Override getMediaDuration()167 public int getMediaDuration() { 168 return (int) mMediaController.getMetadata().getLong( 169 MediaMetadataCompat.METADATA_KEY_DURATION); 170 } 171 172 @Override getCurrentPosition()173 public int getCurrentPosition() { 174 return (int) mMediaController.getPlaybackState().getPosition(); 175 } 176 177 @Override getMediaArt()178 public Drawable getMediaArt() { 179 Bitmap bitmap = mMediaController.getMetadata().getDescription().getIconBitmap(); 180 return bitmap == null ? null : new BitmapDrawable(getContext().getResources(), bitmap); 181 } 182 183 @Override getSupportedActions()184 public long getSupportedActions() { 185 long result = 0; 186 long actions = mMediaController.getPlaybackState().getActions(); 187 if ((actions & PlaybackStateCompat.ACTION_PLAY_PAUSE) != 0) { 188 result |= ACTION_PLAY_PAUSE; 189 } 190 if ((actions & PlaybackStateCompat.ACTION_SKIP_TO_NEXT) != 0) { 191 result |= ACTION_SKIP_TO_NEXT; 192 } 193 if ((actions & PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS) != 0) { 194 result |= ACTION_SKIP_TO_PREVIOUS; 195 } 196 if ((actions & PlaybackStateCompat.ACTION_FAST_FORWARD) != 0) { 197 result |= ACTION_FAST_FORWARD; 198 } 199 if ((actions & PlaybackStateCompat.ACTION_REWIND) != 0) { 200 result |= ACTION_REWIND; 201 } 202 return result; 203 } 204 205 @Override startPlayback(int speed)206 protected void startPlayback(int speed) { 207 if (DEBUG) Log.v(TAG, "startPlayback speed " + speed); 208 if (speed == PLAYBACK_SPEED_NORMAL) { 209 mMediaController.getTransportControls().play(); 210 } else if (speed > 0) { 211 mMediaController.getTransportControls().fastForward(); 212 } else { 213 mMediaController.getTransportControls().rewind(); 214 } 215 } 216 217 @Override pausePlayback()218 protected void pausePlayback() { 219 if (DEBUG) Log.v(TAG, "pausePlayback"); 220 mMediaController.getTransportControls().pause(); 221 } 222 223 @Override skipToNext()224 protected void skipToNext() { 225 if (DEBUG) Log.v(TAG, "skipToNext"); 226 mMediaController.getTransportControls().skipToNext(); 227 } 228 229 @Override skipToPrevious()230 protected void skipToPrevious() { 231 if (DEBUG) Log.v(TAG, "skipToPrevious"); 232 mMediaController.getTransportControls().skipToPrevious(); 233 } 234 } 235