QueueFragment.java revision ff7a534d72423924d6087a011d17634a42199c03
1/* 2 * Copyright (C) 2015 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.example.android.supportv4.media; 18 19import android.content.ComponentName; 20import android.os.Bundle; 21import android.os.RemoteException; 22import android.support.v4.app.Fragment; 23import android.support.v4.content.ContextCompat; 24import android.support.v4.media.MediaBrowserCompat; 25import android.support.v4.media.session.MediaControllerCompat; 26import android.support.v4.media.session.MediaSessionCompat; 27import android.support.v4.media.session.PlaybackStateCompat; 28import android.util.Log; 29import android.view.LayoutInflater; 30import android.view.View; 31import android.view.ViewGroup; 32import android.widget.AdapterView; 33import android.widget.ImageButton; 34import android.widget.ListView; 35 36import com.example.android.supportv4.R; 37 38import java.util.List; 39 40/** 41 * A class that shows the Media Queue to the user. 42 */ 43public class QueueFragment extends Fragment { 44 45 private static final String TAG = "QueueFragment"; 46 47 private ImageButton mSkipNext; 48 private ImageButton mSkipPrevious; 49 private ImageButton mPlayPause; 50 51 private MediaBrowserCompat mMediaBrowser; 52 private MediaControllerCompat.TransportControls mTransportControls; 53 private MediaControllerCompat mMediaController; 54 private PlaybackStateCompat mPlaybackState; 55 56 private QueueAdapter mQueueAdapter; 57 58 private MediaBrowserCompat.ConnectionCallback mConnectionCallback = 59 new MediaBrowserCompat.ConnectionCallback() { 60 @Override 61 public void onConnected() { 62 Log.d(TAG, "onConnected: session token " + mMediaBrowser.getSessionToken()); 63 64 if (mMediaBrowser.getSessionToken() == null) { 65 throw new IllegalArgumentException("No Session token"); 66 } 67 68 try { 69 mMediaController = new MediaControllerCompat(getActivity(), 70 mMediaBrowser.getSessionToken()); 71 } catch (RemoteException e) { 72 Log.e(TAG, "Failed to create MediaControllerCompat.", e); 73 } 74 mTransportControls = mMediaController.getTransportControls(); 75 mMediaController.registerCallback(mSessionCallback); 76 77 ((MediaBrowserSupport) getActivity()).setMediaController(mMediaController); 78 mPlaybackState = mMediaController.getPlaybackState(); 79 80 List<MediaSessionCompat.QueueItem> queue = mMediaController.getQueue(); 81 if (queue != null) { 82 mQueueAdapter.clear(); 83 mQueueAdapter.notifyDataSetInvalidated(); 84 mQueueAdapter.addAll(queue); 85 mQueueAdapter.notifyDataSetChanged(); 86 } 87 onPlaybackStateChanged(mPlaybackState); 88 } 89 90 @Override 91 public void onConnectionFailed() { 92 Log.d(TAG, "onConnectionFailed"); 93 } 94 95 @Override 96 public void onConnectionSuspended() { 97 Log.d(TAG, "onConnectionSuspended"); 98 mMediaController.unregisterCallback(mSessionCallback); 99 mTransportControls = null; 100 mMediaController = null; 101 ((MediaBrowserSupport) getActivity()).setMediaController((MediaControllerCompat) null); 102 } 103 }; 104 105 // Receive callbacks from the MediaController. Here we update our state such as which queue 106 // is being shown, the current title and description and the PlaybackState. 107 private MediaControllerCompat.Callback mSessionCallback = new MediaControllerCompat.Callback() { 108 109 @Override 110 public void onSessionDestroyed() { 111 Log.d(TAG, "Session destroyed. Need to fetch a new Media Session"); 112 } 113 114 @Override 115 public void onPlaybackStateChanged(PlaybackStateCompat state) { 116 if (state == null) { 117 return; 118 } 119 Log.d(TAG, "Received playback state change to state " + state.getState()); 120 mPlaybackState = state; 121 QueueFragment.this.onPlaybackStateChanged(state); 122 } 123 124 @Override 125 public void onQueueChanged(List<MediaSessionCompat.QueueItem> queue) { 126 Log.d(TAG, "onQueueChanged " + queue); 127 if (queue != null) { 128 mQueueAdapter.clear(); 129 mQueueAdapter.notifyDataSetInvalidated(); 130 mQueueAdapter.addAll(queue); 131 mQueueAdapter.notifyDataSetChanged(); 132 } 133 } 134 }; 135 136 public static QueueFragment newInstance() { 137 return new QueueFragment(); 138 } 139 140 @Override 141 public View onCreateView(LayoutInflater inflater, ViewGroup container, 142 Bundle savedInstanceState) { 143 View rootView = inflater.inflate(R.layout.fragment_list, container, false); 144 145 mSkipPrevious = (ImageButton) rootView.findViewById(R.id.skip_previous); 146 mSkipPrevious.setEnabled(false); 147 mSkipPrevious.setOnClickListener(mButtonListener); 148 149 mSkipNext = (ImageButton) rootView.findViewById(R.id.skip_next); 150 mSkipNext.setEnabled(false); 151 mSkipNext.setOnClickListener(mButtonListener); 152 153 mPlayPause = (ImageButton) rootView.findViewById(R.id.play_pause); 154 mPlayPause.setEnabled(true); 155 mPlayPause.setOnClickListener(mButtonListener); 156 157 mQueueAdapter = new QueueAdapter(getActivity()); 158 159 ListView mListView = (ListView) rootView.findViewById(R.id.list_view); 160 mListView.setAdapter(mQueueAdapter); 161 mListView.setFocusable(true); 162 mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 163 @Override 164 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 165 MediaSessionCompat.QueueItem item = mQueueAdapter.getItem(position); 166 mTransportControls.skipToQueueItem(item.getQueueId()); 167 } 168 }); 169 170 mMediaBrowser = new MediaBrowserCompat(getActivity(), 171 new ComponentName(getActivity(), MediaBrowserServiceSupport.class), 172 mConnectionCallback, null); 173 174 return rootView; 175 } 176 177 @Override 178 public void onResume() { 179 super.onResume(); 180 if (mMediaBrowser != null) { 181 mMediaBrowser.connect(); 182 } 183 } 184 185 @Override 186 public void onPause() { 187 super.onPause(); 188 if (mMediaController != null) { 189 mMediaController.unregisterCallback(mSessionCallback); 190 } 191 if (mMediaBrowser != null) { 192 mMediaBrowser.disconnect(); 193 } 194 } 195 196 197 private void onPlaybackStateChanged(PlaybackStateCompat state) { 198 Log.d(TAG, "onPlaybackStateChanged " + state); 199 if (state == null) { 200 return; 201 } 202 mQueueAdapter.setActiveQueueItemId(state.getActiveQueueItemId()); 203 mQueueAdapter.notifyDataSetChanged(); 204 boolean enablePlay = false; 205 StringBuilder statusBuilder = new StringBuilder(); 206 switch (state.getState()) { 207 case PlaybackStateCompat.STATE_PLAYING: 208 statusBuilder.append("playing"); 209 enablePlay = false; 210 break; 211 case PlaybackStateCompat.STATE_PAUSED: 212 statusBuilder.append("paused"); 213 enablePlay = true; 214 break; 215 case PlaybackStateCompat.STATE_STOPPED: 216 statusBuilder.append("ended"); 217 enablePlay = true; 218 break; 219 case PlaybackStateCompat.STATE_ERROR: 220 statusBuilder.append("error: ").append(state.getErrorMessage()); 221 break; 222 case PlaybackStateCompat.STATE_BUFFERING: 223 statusBuilder.append("buffering"); 224 break; 225 case PlaybackStateCompat.STATE_NONE: 226 statusBuilder.append("none"); 227 enablePlay = false; 228 break; 229 case PlaybackStateCompat.STATE_CONNECTING: 230 statusBuilder.append("connecting"); 231 break; 232 default: 233 statusBuilder.append(mPlaybackState); 234 } 235 statusBuilder.append(" -- At position: ").append(state.getPosition()); 236 Log.d(TAG, statusBuilder.toString()); 237 238 if (enablePlay) { 239 mPlayPause.setImageDrawable( 240 ContextCompat.getDrawable(getActivity(), R.drawable.ic_play_arrow_white_24dp)); 241 } else { 242 mPlayPause.setImageDrawable( 243 ContextCompat.getDrawable(getActivity(), R.drawable.ic_pause_white_24dp)); 244 } 245 246 mSkipPrevious.setEnabled((state.getActions() & PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS) 247 != 0); 248 mSkipNext.setEnabled((state.getActions() & PlaybackStateCompat.ACTION_SKIP_TO_NEXT) != 0); 249 250 Log.d(TAG, "Queue From MediaController *** Title " 251 + mMediaController.getQueueTitle() + "\n: Queue: " + mMediaController.getQueue() 252 + "\n Metadata " + mMediaController.getMetadata()); 253 } 254 255 private View.OnClickListener mButtonListener = new View.OnClickListener() { 256 @Override 257 public void onClick(View v) { 258 final int state = mPlaybackState == null ? 259 PlaybackStateCompat.STATE_NONE : mPlaybackState.getState(); 260 switch (v.getId()) { 261 case R.id.play_pause: 262 Log.d(TAG, "Play button pressed, in state " + state); 263 if (state == PlaybackStateCompat.STATE_PAUSED || 264 state == PlaybackStateCompat.STATE_STOPPED || 265 state == PlaybackStateCompat.STATE_NONE) { 266 playMedia(); 267 } else if (state == PlaybackStateCompat.STATE_PLAYING) { 268 pauseMedia(); 269 } 270 break; 271 case R.id.skip_previous: 272 Log.d(TAG, "Start button pressed, in state " + state); 273 skipToPrevious(); 274 break; 275 case R.id.skip_next: 276 skipToNext(); 277 break; 278 } 279 } 280 }; 281 282 private void playMedia() { 283 if (mTransportControls != null) { 284 mTransportControls.play(); 285 } 286 } 287 288 private void pauseMedia() { 289 if (mTransportControls != null) { 290 mTransportControls.pause(); 291 } 292 } 293 294 private void skipToPrevious() { 295 if (mTransportControls != null) { 296 mTransportControls.skipToPrevious(); 297 } 298 } 299 300 private void skipToNext() { 301 if (mTransportControls != null) { 302 mTransportControls.skipToNext(); 303 } 304 } 305} 306