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