18ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik/*
28ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Copyright (C) 2014 The Android Open Source Project
38ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik *
48ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Licensed under the Apache License, Version 2.0 (the "License");
58ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * you may not use this file except in compliance with the License.
68ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * You may obtain a copy of the License at
78ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik *
88ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik *      http://www.apache.org/licenses/LICENSE-2.0
98ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik *
108ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * Unless required by applicable law or agreed to in writing, software
118ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * distributed under the License is distributed on an "AS IS" BASIS,
128ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * See the License for the specific language governing permissions and
148ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik * limitations under the License.
158ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik */
16bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikpackage com.android.onemedia;
17bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
18bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.app.Service;
19bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.content.Intent;
2045f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandlerimport android.graphics.Bitmap;
21dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brownimport android.media.session.MediaSession;
228ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.media.session.PlaybackState;
23bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.os.Bundle;
24bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.os.IBinder;
25bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport android.os.RemoteException;
268ae0f34db936a649ddaf9cdd086c224f6514efebRoboErikimport android.util.Log;
27bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
28bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport com.android.onemedia.playback.IRequestCallback;
29bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport com.android.onemedia.playback.RequestUtils;
30bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
31bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikimport java.util.ArrayList;
32bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
33bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErikpublic class PlayerService extends Service {
34bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private static final String TAG = "PlayerService";
35bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
36bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private PlayerBinder mBinder;
37bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private PlayerSession mSession;
3845f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler    private NotificationHelper mNotifyHelper;
39bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private Intent mIntent;
408ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    private boolean mStarted = false;
41bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
42bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    private ArrayList<IPlayerCallback> mCbs = new ArrayList<IPlayerCallback>();
43bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
44bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
45bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void onCreate() {
468ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        Log.d(TAG, "onCreate");
47bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mIntent = onCreateServiceIntent();
488ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        if (mSession == null) {
498ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSession = onCreatePlayerController();
508ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSession.createSession();
518ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mSession.setListener(mPlayerListener);
5245f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler            mNotifyHelper = new NotificationHelper(this, mSession.mSession);
538ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
54bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
55bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
56bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
57bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public IBinder onBind(Intent intent) {
58bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        if (mBinder == null) {
59bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mBinder = new PlayerBinder();
60bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
61bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return mBinder;
62bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
63bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
64bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
65bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public int onStartCommand(Intent intent, int flags, int startId) {
668ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        Log.d(TAG, "onStartCommand");
67bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return START_STICKY;
68bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
69bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
70bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    @Override
71bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public void onDestroy() {
728ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        Log.d(TAG, "onDestroy");
73bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        mSession.onDestroy();
748ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        mSession = null;
758ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    }
768ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
778ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    public void onPlaybackStarted() {
788ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        if (!mStarted) {
798ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            Log.d(TAG, "Starting self");
808ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            startService(onCreateServiceIntent());
8145f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler            mNotifyHelper.onStart();
828ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mStarted = true;
838ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
848ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    }
858ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
868ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    public void onPlaybackEnded() {
878ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        if (mStarted) {
888ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            Log.d(TAG, "Stopping self");
8945f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler            mNotifyHelper.onStop();
908ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            stopSelf();
918ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            mStarted = false;
928ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
93bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
94bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
95bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected Intent onCreateServiceIntent() {
96bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return new Intent(this, PlayerService.class).setPackage(getBasePackageName());
97bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
98bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
99bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected PlayerSession onCreatePlayerController() {
100bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return new PlayerSession(this);
101bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
102bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
103bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    protected ArrayList<String> getAllowedPackages() {
104bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        return null;
105bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
106bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
1078ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    private final PlayerSession.Listener mPlayerListener = new PlayerSession.Listener() {
1088ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        @Override
1098ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        public void onPlayStateChanged(PlaybackState state) {
1108ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            switch (state.getState()) {
11179fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik                case PlaybackState.STATE_PLAYING:
1128ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    onPlaybackStarted();
1138ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    break;
11479fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik                case PlaybackState.STATE_STOPPED:
11579fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik                case PlaybackState.STATE_ERROR:
1168ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    onPlaybackEnded();
1178ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik                    break;
1188ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik            }
1198ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik        }
1208ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik    };
1218ae0f34db936a649ddaf9cdd086c224f6514efebRoboErik
122bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    public class PlayerBinder extends IPlayerService.Stub {
123bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        @Override
124bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public void sendRequest(String action, Bundle params, IRequestCallback cb) {
125bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (RequestUtils.ACTION_SET_CONTENT.equals(action)) {
126bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mSession.setContent(params);
127bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            } else if (RequestUtils.ACTION_SET_NEXT_CONTENT.equals(action)) {
128bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mSession.setNextContent(params);
129bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
130bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
131bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
132bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        @Override
133bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public void registerCallback(final IPlayerCallback cb) throws RemoteException {
134bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            if (!mCbs.contains(cb)) {
135bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mCbs.add(cb);
136bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                cb.asBinder().linkToDeath(new IBinder.DeathRecipient() {
137bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    @Override
138bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    public void binderDied() {
139bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                        mCbs.remove(cb);
140bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                    }
141bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                }, 0);
142bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
143bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            try {
144bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                cb.onSessionChanged(getSessionToken());
145bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            } catch (RemoteException e) {
146bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                mCbs.remove(cb);
147bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik                throw e;
148bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            }
149bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
150bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
151bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        @Override
152bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        public void unregisterCallback(IPlayerCallback cb) throws RemoteException {
153bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            mCbs.remove(cb);
154bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
155bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
156bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        @Override
157dba34ba35cd2042d9a8fecfda56e2abe7a680badJeff Brown        public MediaSession.Token getSessionToken() throws RemoteException {
15845f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler            if (mSession == null) {
15945f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler                Log.e(TAG, "Error in PlayerService: mSession=null in getSessionToken()");
16045f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler                return null;
16145f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler            }
162bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik            return mSession.getSessionToken();
163bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik        }
16445f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler
16545f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler        @Override
16645f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler        public void setIcon(Bitmap icon) {
16745f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler            mSession.setIcon(icon);
16845f7ee8201efbda59b57b1fe637a1b9ffef25bb6Daniel Sandler        }
169bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik    }
170bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik
171bfa153b64b4e8c2faa39a15e87fc9f0300335f20RoboErik}
172