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