1bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 28ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik/* 38ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Copyright (C) 2014 The Android Open Source Project 48ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 58ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Licensed under the Apache License, Version 2.0 (the "License"); 68ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * you may not use this file except in compliance with the License. 78ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * You may obtain a copy of the License at 88ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 98ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * http://www.apache.org/licenses/LICENSE-2.0 108ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * 118ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Unless required by applicable law or agreed to in writing, software 128ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * distributed under the License is distributed on an "AS IS" BASIS, 138ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 148ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * See the License for the specific language governing permissions and 158ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * limitations under the License. 168ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik */ 17bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikpackage com.android.onemedia; 18bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 1942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.MediaMetadata; 2042ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.session.MediaController; 21550116576cce028d3c435f7c3ae9f6e3b92b5cf2RoboErikimport android.media.session.MediaSession; 2242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.session.MediaSessionManager; 238ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.media.session.PlaybackState; 248ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.os.Bundle; 25bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.os.Handler; 26bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.os.IBinder; 27bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.os.RemoteException; 28550116576cce028d3c435f7c3ae9f6e3b92b5cf2RoboErikimport android.app.Activity; 29bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.content.ComponentName; 30bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.content.Context; 31bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.content.Intent; 32bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.content.ServiceConnection; 3345f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandlerimport android.graphics.Bitmap; 34bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.util.Log; 35bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 36bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport com.android.onemedia.playback.RequestUtils; 37bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 38bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikpublic class PlayerController { 398ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik private static final String TAG = "PlayerController"; 40bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 41bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public static final int STATE_DISCONNECTED = 0; 42bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public static final int STATE_CONNECTED = 1; 43bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 4442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik protected MediaController mController; 45bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik protected IPlayerService mBinder; 46c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik protected MediaController.TransportControls mTransportControls; 47bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 48bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik private final Intent mServiceIntent; 49550116576cce028d3c435f7c3ae9f6e3b92b5cf2RoboErik private Activity mContext; 50bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik private Listener mListener; 51bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik private SessionCallback mControllerCb; 5242ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private MediaSessionManager mManager; 53bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik private Handler mHandler = new Handler(); 54bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 55bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik private boolean mResumed; 5645f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler private Bitmap mArt; 57bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 58550116576cce028d3c435f7c3ae9f6e3b92b5cf2RoboErik public PlayerController(Activity context, Intent serviceIntent) { 59bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mContext = context; 60bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik if (serviceIntent == null) { 61bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mServiceIntent = new Intent(mContext, PlayerService.class); 62bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } else { 63bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mServiceIntent = serviceIntent; 64bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 65bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mControllerCb = new SessionCallback(); 6642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik mManager = (MediaSessionManager) context 67bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik .getSystemService(Context.MEDIA_SESSION_SERVICE); 68bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 69bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mResumed = false; 70bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 71bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 72bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public void setListener(Listener listener) { 73bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mListener = listener; 74bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik Log.d(TAG, "Listener set to " + listener + " session is " + mController); 75bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik if (mListener != null) { 76bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mHandler = new Handler(); 778ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mListener.onConnectionStateChange( 78bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mController == null ? STATE_DISCONNECTED : STATE_CONNECTED); 79bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 80bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 81bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 82bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public void onResume() { 83bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mResumed = true; 84bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik Log.d(TAG, "onResume. Binding to service with intent " + mServiceIntent.toString()); 85bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik bindToService(); 86bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 87bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 88bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public void onPause() { 89bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mResumed = false; 90bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik Log.d(TAG, "onPause, unbinding from service"); 91bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik unbindFromService(); 92bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 93bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 9445f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler public void setArt(Bitmap art) { 9545f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler mArt = art; 9645f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler if (mBinder != null) { 9745f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler try { 9845f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler mBinder.setIcon(art); 9945f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler } catch (RemoteException e) { 10045f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler } 10145f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler } 10245f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler } 10345f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler 104bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public void play() { 1058ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (mTransportControls != null) { 1068ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mTransportControls.play(); 1078ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 108bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 109bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 110bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public void pause() { 1118ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (mTransportControls != null) { 1128ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mTransportControls.pause(); 1138ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 114bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 115bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 116bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public void setContent(String source) { 117bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik RequestUtils.ContentBuilder bob = new RequestUtils.ContentBuilder(); 118bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik bob.setSource(source); 119bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik try { 120bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mBinder.sendRequest(RequestUtils.ACTION_SET_CONTENT, bob.build(), null); 121bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } catch (RemoteException e) { 122bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik Log.d(TAG, "setContent failed, service may have died.", e); 123bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 124bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 125bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 126bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public void setNextContent(String source) { 127bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik RequestUtils.ContentBuilder bob = new RequestUtils.ContentBuilder(); 128bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik bob.setSource(source); 129bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik try { 130bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mBinder.sendRequest(RequestUtils.ACTION_SET_NEXT_CONTENT, bob.build(), null); 131bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } catch (RemoteException e) { 132bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik Log.d(TAG, "setNexctContent failed, service may have died.", e); 133bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 134bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 135bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 13607c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik public void showRoutePicker() { 137ff0215dd64e5fd4ff366930747e7943fcc40c4abJeff Brown // TODO 13807c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik } 13907c7077c54717dbbf2c401ea32d00fa6df6d77c6RoboErik 14045f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler public MediaSession.Token getSessionToken() { 14145f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler if (mBinder != null) { 14245f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler try { 14345f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler return mBinder.getSessionToken(); 14445f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler } catch (RemoteException e) { 14545f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler } 14645f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler } 14745f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler return null; 14845f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler } 14945f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler 150bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik private void unbindFromService() { 151bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mContext.unbindService(mServiceConnection); 152bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 153bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 154bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik private void bindToService() { 155bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mContext.bindService(mServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE); 156bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 157bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 158bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik private ServiceConnection mServiceConnection = new ServiceConnection() { 159bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik @Override 160bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public void onServiceDisconnected(ComponentName name) { 161bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik if (mController != null) { 16214f717a506a0d22facbec07386b06634e0c6a8eeRoboErik mController.unregisterCallback(mControllerCb); 163bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 164bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mBinder = null; 165bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mController = null; 1668ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mTransportControls = null; 167550116576cce028d3c435f7c3ae9f6e3b92b5cf2RoboErik mContext.setMediaController(null); 168bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik Log.d(TAG, "Disconnected from PlayerService"); 169bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 170bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik if (mListener != null) { 1718ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mListener.onConnectionStateChange(STATE_DISCONNECTED); 172bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 173bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 174bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 175bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik @Override 176bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public void onServiceConnected(ComponentName name, IBinder service) { 177bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik mBinder = IPlayerService.Stub.asInterface(service); 178bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik Log.d(TAG, "service is " + service + " binder is " + mBinder); 179550116576cce028d3c435f7c3ae9f6e3b92b5cf2RoboErik MediaSession.Token token; 180bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik try { 181550116576cce028d3c435f7c3ae9f6e3b92b5cf2RoboErik token = mBinder.getSessionToken(); 182bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } catch (RemoteException e) { 183bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik Log.e(TAG, "Error getting session", e); 184bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik return; 185bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 18640495e054591ed4bc110c710c46996ef163664c1RoboErik mController = new MediaController(mContext, token); 187550116576cce028d3c435f7c3ae9f6e3b92b5cf2RoboErik mContext.setMediaController(mController); 18814f717a506a0d22facbec07386b06634e0c6a8eeRoboErik mController.registerCallback(mControllerCb, mHandler); 189c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mTransportControls = mController.getTransportControls(); 19045f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler if (mArt != null) { 19145f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler setArt(mArt); 19245f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler } 193bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik Log.d(TAG, "Ready to use PlayerService"); 194bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 195bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik if (mListener != null) { 1968ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mListener.onConnectionStateChange(STATE_CONNECTED); 1978ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (mTransportControls != null) { 198c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik mListener.onPlaybackStateChange(mController.getPlaybackState()); 1998ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 200bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 201bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 202bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik }; 203bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 20442ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik private class SessionCallback extends MediaController.Callback { 205bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik @Override 2068ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onPlaybackStateChanged(PlaybackState state) { 2078ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (state == null) { 2088ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return; 2098ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 2108ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik Log.d(TAG, "Received playback state change to state " + state.getState()); 211bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik if (mListener != null) { 2128ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik mListener.onPlaybackStateChange(state); 213bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 214bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 2158ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik 2168ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik @Override 2178ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onMetadataChanged(MediaMetadata metadata) { 2188ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik if (metadata == null) { 2198ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik return; 2208ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 22175847b98f39e521a57042c50e69be9e142788d32RoboErik Log.d(TAG, "Received metadata change, " + metadata.getDescription()); 22245f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler if (mListener != null) { 22345f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler mListener.onMetadataChange(metadata); 22445f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler } 2258ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik } 226bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 227bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 228bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik public interface Listener { 2298ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onPlaybackStateChange(PlaybackState state); 2308ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onMetadataChange(MediaMetadata metadata); 2318ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik public void onConnectionStateChange(int state); 232bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik } 233bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik 234bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik} 235