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 */
17package com.android.onemedia;
18
19import android.media.MediaMetadata;
20import android.media.session.MediaController;
21import android.media.session.MediaSession;
22import android.media.session.MediaSessionManager;
23import android.media.session.PlaybackState;
24import android.os.Bundle;
25import android.os.Handler;
26import android.os.IBinder;
27import android.os.RemoteException;
28import android.app.Activity;
29import android.content.ComponentName;
30import android.content.Context;
31import android.content.Intent;
32import android.content.ServiceConnection;
33import android.graphics.Bitmap;
34import android.util.Log;
35
36import com.android.onemedia.playback.RequestUtils;
37
38public 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
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
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
82    public void onResume() {
83        mResumed = true;
84        Log.d(TAG, "onResume. Binding to service with intent " + mServiceIntent.toString());
85        bindToService();
86    }
87
88    public void onPause() {
89        mResumed = false;
90        Log.d(TAG, "onPause, unbinding from service");
91        unbindFromService();
92    }
93
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
104    public void play() {
105        if (mTransportControls != null) {
106            mTransportControls.play();
107        }
108    }
109
110    public void pause() {
111        if (mTransportControls != null) {
112            mTransportControls.pause();
113        }
114    }
115
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
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
136    public void showRoutePicker() {
137        // TODO
138    }
139
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
150    private void unbindFromService() {
151        mContext.unbindService(mServiceConnection);
152    }
153
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
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
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 {
229        public void onPlaybackStateChange(PlaybackState state);
230        public void onMetadataChange(MediaMetadata metadata);
231        public void onConnectionStateChange(int state);
232    }
233
234}
235