1 
2 /*
3  * Copyright (C) 2014 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package com.android.onemedia;
18 
19 import android.media.MediaMetadata;
20 import android.media.session.MediaController;
21 import android.media.session.MediaSession;
22 import android.media.session.MediaSessionManager;
23 import android.media.session.PlaybackState;
24 import android.os.Bundle;
25 import android.os.Handler;
26 import android.os.IBinder;
27 import android.os.RemoteException;
28 import android.app.Activity;
29 import android.content.ComponentName;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.ServiceConnection;
33 import android.graphics.Bitmap;
34 import android.util.Log;
35 
36 import com.android.onemedia.playback.RequestUtils;
37 
38 public class PlayerController {
39     private static final String TAG = "PlayerController";
40 
41     public static final int STATE_DISCONNECTED = 0;
42     public static final int STATE_CONNECTED = 1;
43 
44     protected MediaController mController;
45     protected IPlayerService mBinder;
46     protected MediaController.TransportControls mTransportControls;
47 
48     private final Intent mServiceIntent;
49     private Activity mContext;
50     private Listener mListener;
51     private SessionCallback mControllerCb;
52     private MediaSessionManager mManager;
53     private Handler mHandler = new Handler();
54 
55     private boolean mResumed;
56     private Bitmap mArt;
57 
PlayerController(Activity context, Intent serviceIntent)58     public PlayerController(Activity context, Intent serviceIntent) {
59         mContext = context;
60         if (serviceIntent == null) {
61             mServiceIntent = new Intent(mContext, PlayerService.class);
62         } else {
63             mServiceIntent = serviceIntent;
64         }
65         mControllerCb = new SessionCallback();
66         mManager = (MediaSessionManager) context
67                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
68 
69         mResumed = false;
70     }
71 
setListener(Listener listener)72     public void setListener(Listener listener) {
73         mListener = listener;
74         Log.d(TAG, "Listener set to " + listener + " session is " + mController);
75         if (mListener != null) {
76             mHandler = new Handler();
77             mListener.onConnectionStateChange(
78                     mController == null ? STATE_DISCONNECTED : STATE_CONNECTED);
79         }
80     }
81 
onResume()82     public void onResume() {
83         mResumed = true;
84         Log.d(TAG, "onResume. Binding to service with intent " + mServiceIntent.toString());
85         bindToService();
86     }
87 
onPause()88     public void onPause() {
89         mResumed = false;
90         Log.d(TAG, "onPause, unbinding from service");
91         unbindFromService();
92     }
93 
setArt(Bitmap art)94     public void setArt(Bitmap art) {
95         mArt = art;
96         if (mBinder != null) {
97             try {
98                 mBinder.setIcon(art);
99             } catch (RemoteException e) {
100             }
101         }
102     }
103 
play()104     public void play() {
105         if (mTransportControls != null) {
106             mTransportControls.play();
107         }
108     }
109 
pause()110     public void pause() {
111         if (mTransportControls != null) {
112             mTransportControls.pause();
113         }
114     }
115 
setContent(String source)116     public void setContent(String source) {
117         RequestUtils.ContentBuilder bob = new RequestUtils.ContentBuilder();
118         bob.setSource(source);
119         try {
120             mBinder.sendRequest(RequestUtils.ACTION_SET_CONTENT, bob.build(), null);
121         } catch (RemoteException e) {
122             Log.d(TAG, "setContent failed, service may have died.", e);
123         }
124     }
125 
setNextContent(String source)126     public void setNextContent(String source) {
127         RequestUtils.ContentBuilder bob = new RequestUtils.ContentBuilder();
128         bob.setSource(source);
129         try {
130             mBinder.sendRequest(RequestUtils.ACTION_SET_NEXT_CONTENT, bob.build(), null);
131         } catch (RemoteException e) {
132             Log.d(TAG, "setNexctContent failed, service may have died.", e);
133         }
134     }
135 
showRoutePicker()136     public void showRoutePicker() {
137         // TODO
138     }
139 
getSessionToken()140     public MediaSession.Token getSessionToken() {
141         if (mBinder != null) {
142             try {
143                 return mBinder.getSessionToken();
144             } catch (RemoteException e) {
145             }
146         }
147         return null;
148     }
149 
unbindFromService()150     private void unbindFromService() {
151         mContext.unbindService(mServiceConnection);
152     }
153 
bindToService()154     private void bindToService() {
155         mContext.bindService(mServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
156     }
157 
158     private ServiceConnection mServiceConnection = new ServiceConnection() {
159         @Override
160         public void onServiceDisconnected(ComponentName name) {
161             if (mController != null) {
162                 mController.unregisterCallback(mControllerCb);
163             }
164             mBinder = null;
165             mController = null;
166             mTransportControls = null;
167             mContext.setMediaController(null);
168             Log.d(TAG, "Disconnected from PlayerService");
169 
170             if (mListener != null) {
171                 mListener.onConnectionStateChange(STATE_DISCONNECTED);
172             }
173         }
174 
175         @Override
176         public void onServiceConnected(ComponentName name, IBinder service) {
177             mBinder = IPlayerService.Stub.asInterface(service);
178             Log.d(TAG, "service is " + service + " binder is " + mBinder);
179             MediaSession.Token token;
180             try {
181                 token = mBinder.getSessionToken();
182             } catch (RemoteException e) {
183                 Log.e(TAG, "Error getting session", e);
184                 return;
185             }
186             mController = new MediaController(mContext, token);
187             mContext.setMediaController(mController);
188             mController.registerCallback(mControllerCb, mHandler);
189             mTransportControls = mController.getTransportControls();
190             if (mArt != null) {
191                 setArt(mArt);
192             }
193             Log.d(TAG, "Ready to use PlayerService");
194 
195             if (mListener != null) {
196                 mListener.onConnectionStateChange(STATE_CONNECTED);
197                 if (mTransportControls != null) {
198                     mListener.onPlaybackStateChange(mController.getPlaybackState());
199                 }
200             }
201         }
202     };
203 
204     private class SessionCallback extends MediaController.Callback {
205         @Override
onPlaybackStateChanged(PlaybackState state)206         public void onPlaybackStateChanged(PlaybackState state) {
207             if (state == null) {
208                 return;
209             }
210             Log.d(TAG, "Received playback state change to state " + state.getState());
211             if (mListener != null) {
212                 mListener.onPlaybackStateChange(state);
213             }
214         }
215 
216         @Override
onMetadataChanged(MediaMetadata metadata)217         public void onMetadataChanged(MediaMetadata metadata) {
218             if (metadata == null) {
219                 return;
220             }
221             Log.d(TAG, "Received metadata change, " + metadata.getDescription());
222             if (mListener != null) {
223                 mListener.onMetadataChange(metadata);
224             }
225         }
226     }
227 
228     public interface Listener {
onPlaybackStateChange(PlaybackState state)229         public void onPlaybackStateChange(PlaybackState state);
onMetadataChange(MediaMetadata metadata)230         public void onMetadataChange(MediaMetadata metadata);
onConnectionStateChange(int state)231         public void onConnectionStateChange(int state);
232     }
233 
234 }
235